【问题标题】:Generic repository factory and service composition通用存储库工厂和服务组合
【发布时间】:2011-04-27 12:06:00
【问题描述】:

previous question 中,人们帮助我解决了存储库生命周期问题,现在有一个问题是如何使其在复合服务中正常工作。

假设我有服务:

public class OrderService : IOrderService 
{         
     IRepository<Order> orderRepository;          

     public OrderService(IRepositoryFactory repositoryFactory) 
     {
        orderRepository = repositoryFactory.GetRepository<Order>();
     }

     public void CreateOrder(OrderData orderData) 
     {
        ...
        orderRepository.SubmitChanges();
     }
}

public class ReservationService : IReservationService 
{
     IRepository<Reservation> reservationRepository;

     public ReservationService(IRepositoryFactory repositoryFactory) 
     {
        reservationRepository = repositoryFactory.GetRepository<Reservation>();
     }

     public void MakeReservations(OrderData orderData)   
     {
         ...
         reservationService.SubmitChanges();
     }
}

现在是有趣的部分 - 组合服务:

public class CompositionService : ICompositionService {
     IOrderService orderService;
     IReservationService reservationService;

     public CompositionService(IOrderService orderService, IReservationService reservationService) 
     {
        this.orderService = orderService;
        this.reservationService = reservationService;
     }

     public void CreateOrderAndMakeReservations(OrderData orderData) 
     {
        using (var ts = new TransactionScope()) 
        {
           orderService.CreateOrder(orderData);
           reservationService.MakeReservations(orderData);
           ts.Complete();
        }
     }
}

问题是,如果 IRepositoryFactory 的生活方式是短暂的,它将无法正常工作(因为您将获得两个不同的数据上下文,并且需要启用分布式事务,我们试图避免这种情况)。任何想法如何正确写这个?

【问题讨论】:

    标签: c# castle-windsor ioc-container


    【解决方案1】:

    我的观察:

    1. 一般来说,工厂应该是单例的。如果您的工厂不是单例,那么您可能只是在其后面隐藏了另一个工厂。
    2. 工厂用于按需创建对象。您的代码只是在构造函数中创建了一个存储库,因此我看不出这与在构造函数中将存储库作为直接注入参数之间的区别。

    在我看来,这些都是解决更基本问题(在您的第一个问题中描述)的解决方法,而这些解决方法只会使问题变得更加复杂。除非你解决了根本问题,否则你最终会得到一个复杂的依赖模式和一个臭代码。

    【讨论】:

    • 那么问题是如何解决根本问题?不敢相信,以前没有人遇到过这个问题。
    【解决方案2】:

    IMO - 这是一个分布式事务场景。

    在您提到的示例中,OrderServiceReservationService 使用相同的数据上下文是隐藏在代码中的实现细节。

    我认为通过将服务调用包装在 TransactionScope 中将这些知识传递给 CompositionService 是不正确的,因为现在组合服务知道共享数据上下文,因此需要使用 TransactionScope 来运行代码正确。

    在我看来,组合服务代码应该是这样的:

    try{
     if(orderService.TryCreateOrder(orderData)){
       if(reservationService.TryMakeReservation(orderData)){
          reservationService.Commit();
          orderService.Commit();
       }
       else{
         orderService.TryRollbackOrder(orderData);
         throw new ReservationCouldNotBeMadeException();
       }
     }
     else{
      throw new OrderCouldNotBeCreatedException();
     }
    }
    catch(CouldNotRollbackOrderServiceException){
     // do something here...
    }
    catch(CouldNotCommitServiceException){
     // do something here...
    }
    

    在这种情况下,OrderService.TryCreateOrder 方法将插入一个具有 PendingReservation 状态或其他相关状态的订单,表明订单已插入,但尚未完成。在服务上调用提交时,此状态将发生变化(UnitOfWork 模式?)

    在这种情况下,服务的实现细节对服务的消费者是完全隐藏的,而组合也是可能的,独立于底层的实现细节。

    HTH。

    【讨论】:

      猜你喜欢
      • 2013-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      • 2019-04-23
      相关资源
      最近更新 更多