DDD中聚合根的行为应该是不是演员?

时间:2017-08-28 21:33:25

标签: architecture entity domain-driven-design aggregateroot

我的英语不好,所以我会举两个例子。在这个例子中,让我们从DDD中删除一些重要的东西,主要是事情的本质。

如何从DDD的角度做到这一点?

我们有两个聚合根,SellerAdvertSeller可以在以下示例中修改Advert

1

如果模型应该反映真实的业务逻辑。然后,Seller必须更改Adverts。即客户端层调用聚合changeAdvertName()的方法changeAdvertCost()Seller。顺便说一句,这提供了访问检查等优势。我们可以看到Seller只能修改自己的Adverts。这是第一个选择。

    //Client layer call seller.changeAdvertName(name)

    //AR Seller
    class Seller{
        adverts
        changeAdvertName(advertId, name){
            adverts[advertId].changeName(name)
        }
        changeAdvertCost(advertId, cost){
            adverts[advertId].changeCost(cost)
        }
    }

    //AR Advert
    class Advert{
        name
        cost
        changeName(name){
            this.name = name
        }
        changeCost(cost){
            this.cost = cost
        }
    }

2

另一种变体,客户端层可以直接从聚合changeName调用方法changeCostAdvert。我多次看到这个实现。

    //Client layer call advert.changeName(name)

    //AR Advert
    class Advert{
        name
        cost
        changeName(name){
            this.name = name
        }
        changeCost(cost){
            this.cost = cost
        }
    }

您如何看待这些选择?它们是否对DDD有效 实施?从DDD的角度来看哪一个更正确和合乎逻辑?

谢谢!

2 个答案:

答案 0 :(得分:4)

  

它们是否对DDD实施有效?

域驱动设计中的一个重要思想是一致性边界的概念 - 聚合是一个可以单独修改的状态边界 - 而不需要查看聚合之外的任何状态。

主要的好处是客户端代码不需要担心管理一致性规则;这个责任总是存在。

另一个好处是对一个聚合的修改不需要阻止对另一个聚合的修改。

嵌套聚合根,通过让一个聚合包含对另一个聚合的引用,会产生一些混乱的想法;尝试修改广告的线程可能会干扰尝试修改广告卖方的其他线程。

在单个聚合中拥有多个实体基本上没有任何问题。例如,您可以合理地将卖方实体和广告实体合并为单个卖方聚合,并通过对广告进行的所有更改通过卖方来强制执行一致性保证。然而,重要的是要认识到,在这种设计中,广告本身不是聚合根。

让广告成为自己的聚合根,处理自己的一致性规则也没有错,而卖家则生活在不同的聚合中。

在这个简单的例子中,卖方只是推迟对广告的更改,将它们彼此分开是有意义的,这样可以同时修改同一卖方的不同广告。

如果有一些跨越多个广告的关键域不变量,那么您可能需要将它们全部拉入一个集合中,这可能存在于卖方聚合中。

  

我的想法是,在实际业务流程中,卖方专门创建广告并更改广告。但是,抽象客户端层不是创建和更改广告。那么,你能帮忙理解吗?

     

事实证明,在真实的商业世界中,卖家可以创建(),drop(),modify()... - >广告。但在DDD聚合中,卖方只能实现创建(广告)行为吗?

这真的不是DDD特有的;它更像是“面向对象”编程的反映(如Java所理解的那样)。行为 - 也就是说,状态的变化 - 通过向管理该状态的实体发送消息而发生。

面向对象的习语实际上与英语语法不太匹配。我们通常会写“卖家修改广告” - 主题 - 动词 - 对象形式。但是在面向对象编程的语法中,对象响应命令性时态消息(命令)而改变它们自己的状态。

List.addItem(...) - 我们没有修改列表,我们正在向列表发送一个命令,上面写着:“修改自己的状态”。

同样,卖方不会修改广告的状态;她正在发送一条消息,描述广告应该改变的方式,并由广告来做。

这是故意的:这意味着卖方可以与广告协作,而无需了解广告的实施,这意味着我们可以在不破坏卖家的情况下随时替换该实施。

答案 1 :(得分:0)

聚合根是一致性边界,以确保域模型保持可靠状态。 许多DDD从业者都知道这一点。

  

交易应该,而不是跨越聚合边界。在单独的事务中更新另一个聚合使用域事件。 more

从这个角度来看第二个选项会更有效,因为你有2个聚合根。