领域内的对象交互问题

聚合根对象中一般都存在着对本领域内其他对象的引用,当修改内部引用对象的状态的时候,由聚合根上的方法发出相应的内部领域事件,然后在聚合根上的内部领域事件处理器来处理相关的领域事件,同时修改状态,那同一个聚合中的对象之间交互采用引用调用修改呢?还是从新发出一个事件来进行修改呢?
比如User聚合根中存在这Address的引用(假定该Address是User聚合中的一个实体,而非值对象),此时命令处理器发出了"修改地址"的命令,那么在User聚合根中的changeAddress(Address newAddress)方法会被命令处理器调用,那在changeAddress方法体内就可以发出一个“内部领域事件”---AddressChangedEvent,且在User中存在这相应的handle(AddressChangedEvent event)方法来对该事件进行处理(及修改User对象的状态),此时问题就出现了:有两种方式进行处理:
1、直接调用Address中的另一个方法,来修改该Address的状态(直接使用引用)
2、发出一个事件,由Address来处理该事件,并改变Address的状态(事件机制)
第一种的意图就是聚合根处理自己的内部状态,如果是引用则直接调用其set方法修改其状态;第二种则是在聚合根的事件处理中再次发出事件,然后让引用对象自己处理,但会导致领域内的事件非常多,导致事件风暴
不知道这两种方式哪种比较好,欢迎讨论....
[该贴被wilsonp于2014-04-26 13:02修改过]

聚合内部直接方法调用,如正常一样,两个聚合之间通过事件,引入事件意味着弱一致性,这是要注意的。

嗯,我也比较倾向于在领域内交互使用引用直接调用,这样比较简单,也使得DDD在持久化整个聚合时比较简单,不会出现事务不一致的问题;聚合之间的交互则应该用事件来进行解耦,考虑到banq提出的弱一致性,所以可以考虑banq之前提出的反馈事件的机制,这样一来,领域内和领域外的交互就解决了...

2014-04-28 06:56 "@banq"的内容
引入事件意味着弱一致性,这是要注意的。 ...

关于弱一致性的有点疑问:
1、在核心领域层面,弱一致性表示为不同聚合的状态一致性;而在数据同步层面,则和通常的事务差不多(即CQRS的数据同步事件处理器将数据改变同步到readDb中)
2、当在同步的时候就有一个问题,当User聚合中的Adderss实例的状态修改了,同时导致了User聚合根中的“某个关联属性”也发生了改变(假定这两个修改是事务性的,且一个是直接状态,一个是引用状态),此时产生了2个事件2个事件处理器,而一般这种同步的实现都是采用异步的方式来实现的,即2个事件的处理在不同的线程中进行处理,问题就出来了,如何保证不同线程之间的事务一致性呢?当然,也可以将2个事件处理合并起来,但这种做法明显有违“单一职责”原则,因为是对不同属性的同步(也许可以有其他的方式可以解决),但这是一个难点...

2014-04-28 17:36 "@wilsonp"的内容
如何保证不同线程之间的事务一致性呢? ...

弱一致性就是听任其最终一致性,业务上正好也是允许的,Eric在这个帖子http://www.jdon.com/44491谈及了,两个上下文之间是适合使用最终一致性的。

当然,最终一致性或弱一致性不代表性能低,数据同步就滞后,通过并发机制反而性能高,延迟低,吞吐量也大了。