【问题标题】:how to implement services and repositories on onion architecture?如何在洋葱架构上实现服务和存储库?
【发布时间】:2012-05-13 14:53:36
【问题描述】:

这几天我一直在研究洋葱架构。我了解依赖项应该始终朝向中心,以及如何使用依赖项注入来实现这一点。但是我有几个问题我还是想不通。

  1. 模型(或实体)能否引用存储库接口或服务接口?

    例如:Order 实体具有通过Oder.DeliveryZip 属性建立的DeliveryCity 关系,该属性不是外键,但是是唯一的。要获得 City 的邮编,我必须致电 ICityRepository.FindByZip(zip)

    我的模型中有以下代码

    class Order
    { 
        . . .
    
        [Inject]
        public ICityRepository CityRepository { get; set; }
    
        private City _dCity;
    
        public City DeliveryCity {
            get {
                if (_dCity == null)
                    _dCity = this.CityRepository.FindByZip(this.DeliveryZip);
    
                return _dCity;
            }
        }
        . . .
    }
    
  2. 上面的代码会有什么问题?它应该改用域服务吗?

  3. 应该在核心层还是在基础设施层定义域服务实现?

【问题讨论】:

    标签: .net domain-driven-design ddd-repositories onion-architecture ddd-service


    【解决方案1】:

    这是工厂适合域的地方。 OrderFactory 可以接受依赖,例如对 IOrderRepository 的依赖以及对 ICityRepository 的依赖。当工厂用于创建(或重构)一个 Order 实体时,工厂可以查找 City 并相应地设置 Order 属性。或者,正如 herzmeister 建议的那样,使用 Lazy 进行设置,以便仅在需要时执行查找。

    【讨论】:

    • 这很有意义!我在问自己“我怎么会错过呢?”!谢谢!
    • 这是一个错误。 DDD工厂不负责重构。重构是一个对象的中间生命,工厂只关心生命的开始。请看这个答案:stackoverflow.com/a/10264669/625332
    • 我不同意。工厂用于创建对象的实例。它们可以在对象生命周期的开始或用于重构。它们可能是具有两种方法的同一个类,也可能是两个不同的类。无论哪种方式,我都同意工厂在每种情况下的行为方式存在差异。我通常将重构工厂作为存储库的依赖项,它委托给工厂使用从数据存储中检索到的数据来创建和重构新实例。有关更多信息,请参阅 Evans pg 145:“重构存储对象”
    【解决方案2】:
    1. 怎么样

      private Lazy<City> _dCityLazy;
      
      public City DeliveryCity {
          get {
              return _dCityLazy.Value;
          }
      }
      

      你会通过某种机制在哪里注入Lazy&lt;City&gt;

    2. 在这个例子中,你可以灵活地从外部注入。

    3. 我想说这真的取决于特定域服务的作用和使用位置。

    【讨论】:

    • 通过 IoC 注入城市会导致向依赖注入器添加业务规则,这非常糟糕。我不确定这就是你提出的建议。
    • 当然,依赖注入器中的业务规则确实很糟糕,但不必如此。还有很多其他的可能性。两者之间可以有域服务。或者,简单的 id 查找显然是存储库的工作,携带将引用 Lazy&lt;T&gt; 的委托的实际方法。一般来说,我只是想保持我的实体简单,即不了解实际持久性的结构,即不引用任何服务或存储库。
    【解决方案3】:

    上面的代码会有什么问题?它应该改用域服务吗?

    这里需要考虑两件事:

    1. ICityRepository 不是 Order 的真正依赖项,换句话说,Order 的其他方法不需要它。真正的依赖是对象不能没有的东西。因此,您可能需要考虑将其作为参数传递给诸如“GetDeliveryCity”之类的方法(有关详细信息,请参阅this)。

    2. 按邮政编码查找城市似乎不是订单的责任。要使 Order 成为 cohesive,它必须只处理与订单相关的功能。您可能希望将此功能从订单类中移除。

    应该在核心层还是在基础设施层定义域服务实现?

    如果这是真正的领域服务(不是应用程序服务),则在核心内部。

    【讨论】:

      猜你喜欢
      • 2012-09-01
      • 1970-01-01
      • 2023-04-02
      • 2013-06-30
      • 2016-08-12
      • 2011-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多