【问题标题】:Domain Model Association Lazy Loading领域模型关联延迟加载
【发布时间】:2014-01-15 00:38:15
【问题描述】:

我目前面临处理聚合实体之间关联的问题。

考虑以下示例:

现在,我们有一个 ,,User" Entity,它也是我的聚合根。他可以有一个与之关联的 ,,Product" 和许多 ,,Aliases"。我目前需要的是能力在域模型中按需检索相关的 ,,Product" 和 ,,Aliases"。用户由 UserFactory 创建,可以单独使用,也可以在从持久数据创建实体时在 UserRepository 中使用。

<?php
class User {
   private $id;

   private $aliases;
   private $product;

   public function isEligibleForCompanyPromotion() {
      //I need a good way to populate this without a performance bottleneck. 
      $product = $this->product;
      [.. code comparing things between User and Product begins ..]
   }     

}

这样做的原因是因为我们的业务逻辑(如您在示例中看到的)很大程度上依赖于对象之间的关联,我认为与对象之间的关联相关的逻辑应该在领域模型中完成(或者这应该是搬出去了?)

我考虑了以下解决方案:

1) 只需在构造用户时加载所有内容(相关的 Product 和 Aliases )。

优点:

  • 有效吗?

缺点:

  • 大性能问题(不幸的是,我正在开发实时高负载系统,所以不能忽略)

2) 将关系存储库注入到领域模型中

  private $productRepository;
  private $aliasesRepository;
  [...]

}

优点:

  • 作品..

缺点:

  • 违背 (imo) DDD 的目的,要求用户在内部拥有存储库(因此域模型与持久性相结合..)

3) 将关联相关的逻辑委托到域模型之外(可能委托给域服务和策略?)

优点:

  • 也有效

缺点:

  • 其实我觉得这会导致贫血的领域模型,因为我们的大部分业务逻辑都是基于对象的关系,所以很多代码会从领域对象中移出,这没有任何意义。李>

4) 创建一个专门的关系对象来处理关系:

<?php
class UserFactory { 

private $relationshipFactory;

public function createUser($persistenceData) {
    $user = new User();
    [.. creating of User, populating data etc .. ]
    $user->product = $this->relationshipFactory->createUserProductRelationship($user);
}

}


class UserProductRelationship {

    private $user;
    private $product;
    private $productRepository;

    [.. productRepository is being injected within relationshipFactory, and user is  provided ..]

    public function loadProduct() { 
      [.. load the product based on the relationship criterias ..]
    }

    [.. calls to this object are proxied to lazy-loaded product via __call, __get etc. )
}

优点:

  • 也有效

缺点:

  • 循环依赖(用户需要在内部拥有 UserProductRelationship 并依赖它。UserProductRelationship 需要与 User 实体一起提供。将这两个类结合起来会导致场景 #2)。

也许我没有正确理解某些东西。如果有人有建议,我很乐意听到。

谢谢!

【问题讨论】:

    标签: php model domain-driven-design domain-data-modelling


    【解决方案1】:

    如果某些职责不属于任何对象或领域对象需要太多不相关的数据来解决问题,则引入规范对象。

    您需要的是 EligibleForCompanyPromotionSpecification,例如:

    class EligibleForCompanyPromotion {
        private $productRepository;
        private $aliasesRepository;
    
        public function isSatisfiedBy(User user) {
           //I need a good way to populate this without a performance bottleneck. 
           $product = $productRepository.find(user.productId);
           [.. code comparing things between User and Product begins ..]
    }   
    
    class User {
       private $id;
    
       private $aliasesId;//only identifiers needed
       private $productId;//only identifiers needed 
    

    在这种情况下,域逻辑不会泄漏到应用层,我们不必将存储库注入到用户中。

    【讨论】:

    • 所以,或多或少,这是来自答案 3 的概念?我应该将域对象之外的两个域对象之间的比较委托给此类策略/服务类吗?
    • @user1009783 规范也是一个领域概念。当您想要执行一些验证并将验证主题与验证规则(通常会引入不必要的依赖关系)解耦时,通常会使用它。请参考Specification Pattern
    • 好的。明白了。如何在所述实体中检索数据(例如,但考虑到我们不想在验证中这样做)?据我了解,存储库应该这样做。但是,加载整个对象图(在我的例子中:用户和他的别名和他的产品)是无效的,我需要一种延迟加载的方法。我想到的是4)的实现,创建实现相关实体接口的“代理”对象,但绑定到存储库并在第一次使用时加载实际实体。或者我应该完全避免域对象中的关系?
    • @user1009783 延迟加载有时被认为是一种代码异味,表明域模型被滥用于查询。你可以看看这个question。通常,如果要检索实体内的数据,则必须将存储库或服务注入域模型。但这被认为是antipattern。另一方面,规范可以缓解这些问题:)
    • 你不觉得这让领域模型有点乏力吗?我的意思是,除了更新自身的状态之外,这样的领域模型还能做什么,而这还不足以完成有意义的业务流程?我想有人可能会争辩说这应该委托给服务以协调多个实体之间的更改?这可能会奏效。虽然我内心仍然有问题,因为我觉得我的实体..不再耦合,没有该服务就不能用作关系。
    猜你喜欢
    • 1970-01-01
    • 2012-03-12
    • 2011-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-08
    • 1970-01-01
    相关资源
    最近更新 更多