2013-01-10 11:11 "@thinkjava"的内容
感谢banq老师,这就是DDD中的聚合,边界概念 ...

关键问题是划分聚合边界以后,如何设计两个聚合边界之间的通讯和耦合,建立防腐层等等。聚合边界之间通讯只能通过聚合根也就是实体进行的,或者专门负责通讯的类,如同一个国家的外交部是专门负责对其他国家交互的,国家的首都是聚合根,国家有自己的边界。

聚合体之间使用异步消息进行通信不失去为最耦合的一种对象解耦方式。

这个案例中Order和Book分别是不同聚合边界中根,就不能直接将Order和Book进行耦合关联了,Order边界内的Book可能是一个值对象,而且此book非聚合根Book。比如一个Book下订单的是第一版,新的第二版出来了,两个Book就不同了。

[该贴被banq于2013-01-12 08:36修改过]

2013-01-12 08:22 "@banq"的内容
这个案例中Order和Book分别是不同聚合边界中根,就不能直接将Order和Book进行耦合关联了,Order边界内的Book可能是一个值对象,而且此book非聚合根Book。比如一个Book下订单的是第一版,新的第二版出来了,两个Boo ...

DDD中两个聚合根不能关联是有明确说明吗?不过,这样感觉不好,那Order中的Book就是值对象了,如果要给一个Book增加Comments,就得先Repository.load得到Order,通过Order得到Book list,再根据Book list一个个得到Book的聚合根,再调用其中的addComments,这有些太麻烦了吧

2013-01-12 23:04 "@thinkjava"的内容
DDD中两个聚合根不能关联是有明确说明吗 ...

参考这个帖子:聚合根相关理解,这样对吗?,聚合根代表一种封闭性很好的大比例对象,相互之间使用消息传递才更加符合面向对象,这个原理见:面向对象编程的关键目标

我前面关于:订单里面的Book和用于展示的Book可能不是同一个BOOk,你在淘宝网买过东西吗?买过后过段时间再去买,找到原来的订单,进入订单的商品页面,你会发现提示,这个商品已经不是最新的商品。如何进行设计呢?是通过状态还是改变类型呢?聚合根是唯一的吗

DDD分析是及早暴露复杂性,而不是在分析阶段画几张图糊弄一下,将复杂性推给代码实现阶段。
[该贴被banq于2013-01-13 11:44修改过]

2013-01-13 10:39 "@banq"的内容
我真不愿意重复我说的话,订单里面的Book和用于展示的Book可能不是同一个BOOk,你在淘宝网买过东西吗?买过后过段时间再去买,找到原来的订单,进入订单的商品页面,你会发现提示,这个商品已经不是最新的商品。 ...

->过段时间商品已经不是最新的商品了,也就是说Book已经被更新了,但是有一个条件,Book ID(AggregateRootID)并没有变化,这符合聚合根的全局维一性(全局标实全局唯一),这是不是并不影响Order持有Book作为聚合根的引用

通过聚合边界进行切分,切了不分,藕断丝连还是耦合,因此聚合体之间不能直接关联耦合,否则我给你图上画几个圈,是因为我想画玩吗?你不会认识到这是一个重大改变?

只保留高聚合关联,去除普通关联,这是可以在书里找到的基本原则。

关于聚合全局唯一性标识,这不是聚合体之间可以直接引用,最后一个大系统实际上是一个大蜘蛛网,这和er或关系数据库分析图有区别吗?

2013-01-13 13:44 "@banq"的内容
只保留高聚合关联,去除普通关联,这是可以在书里找到的基本原则。 ...

高内聚、低耦合(高数据耦合、低关联耦合)
程序设计基本原则,但与聚合根之间能不能导航关联没有必然联系

我设计时,领域层的各个模块并非平行的,还被我细分为:作业层、业务层和分析决策层上层,“业务层”的聚合对象完全可以直接导航到下层“作业层”的对象。同为“业务层”的聚合对象使用数据耦合,聚合根之间能不能关联、导航,还得具体问题具体分析。

(领域建模切不可被架构绑架)
[该贴被clonalman于2013-01-13 14:13修改过]

这确实是一个比较难分析的事情,需要靠经验决定,多谢banq和clonalman
结论:两个聚合根之间不能直接关联,可以通过值对象作桥梁间接关联

    谈一下我的思路,我仔细看了一下这个“网上书店”的案例,可分为这么几个场景:”浏览商品“——”放入购物车“——”确认订单“——”付款“——”发货“,那么领域模型也就出来了,如下所示:

领域模型----------- 聚合根

商品-----------------Item

购物车—————cart

订单——————order

支付——————payment

发货——————cargo
[该贴被flyzb于2013-01-14 23:39修改过]

我个人感觉cart和payment可能不是聚合根,而是值对象,可以说Cart可以作为Order.submit的参数传入,Payment是个动司,属于行为,作以作为Order的方法使用,对一个Order调用payment后就会执行付款动作,与Account中的金额发生关系,与银行账号也发生关系等

2013-01-15 11:45 "@thinkjava"的内容
我个人感觉cart和payment可能不是聚合根,而是值对象

没有什么绝对的聚合根,聚合根是一个领域模型的聚合中心,也就是说聚合根的确认是与领域模型的划分息息相关的。如果你认为cart和payment不是聚合根,那么也就是说你不承认“购物车”和“支付”这两个领域模型的存在,那么请问你是如何切分业务的?
[该贴被flyzb于2013-01-15 20:39修改过]

说错了,Cart是实体,里面维护一个商品列表,相当于List<Book>,Payment是个行为,订单具有支付行为,这也符合实际业务,支付总是针对某个订单的,执行订单的payment方法后,将产生OrderPaiedEvent事件进行相关业务处理,业务切分之前banq老师已经做过切分了,三个子领域:订单,书籍,物流

    我是这样考虑的,不要简单地认为一个"购物车Cart"很简单,因为“对用户购物行为的分析”是当前网店非常重要的内容。同时,付款也是网上商店的重要组成部分,是“信用卡、支付宝或者什么”。
    其实,我想指出的是,你一上来没有详细说明并分析业务,就弄出一个DDD的UML,有些本末倒置了。

    认真分析业务,而不是随便拿出一个例子,至少是你实战过的,然后切分领域模型,才是正道。
[该贴被flyzb于2013-01-15 22:00修改过]

五一好好研究一下:)