本帖提到的关于用“让领域模型内所有实体对象都平等”的思路去解决DDD+Event Sourcing带来的模型重构问题,我在昨天和今天通过用这种方法对一些小的例子进行建模,发现所有实体对象全部平等的思路有点过。通过进一步思考,我有了一些新的想法。
那就是我们应该用更平和的多角度思考的心态去建模,重点在于理性的识别对象之间的关系。
我的最新结论如下:
1. 如果对象之间是严格的内聚关系,则还是要尊重这种关系,不能强制让这些对象地位平等,即不能对那些被内聚的子实体也采用Event Sourcing;如订单与订单明细,订单必须内聚至少一个订单明细才是一个有效的订单;即订单会关注和管理其内部维护的订单明细;对于订单明细而言,只能属于一个订单,而且永远只能属于这个订单。这种情况下,我也认为只有订单才有必要有事件,订单明细不需要有;
2. 如果对象之间是组合的关系,则需要让这些对象地位平等,对组合关系中的所有对象都应该采用Event Sourcing;如汽车和轮子,虽然从汽车的角度去看,也是和订单一样,汽车必须具有四个轮子才是一辆有效的汽车;但是从轮子角度去看,轮子可以属于这辆汽车,也可能属于另外一辆汽车。比如之前属于汽车A,后来汽车A坏了,但是轮子没坏,所以我们把该轮子装在另外一辆汽车B上了。从这个例子可以看出,汽车与轮子之间的关系没有像订单与订单明细那么内聚,汽车与轮子是组合关系。实际上,现实生活中完全有只造轮子的公司,它们制造出来的轮子被一些汽车制造商买去,然后组装成一辆辆汽车;所以,显然轮子在某些场景下有独立存在的意义,因此我们就有必要独立关注它的生命周期,即我们也需要对轮子采用EventSourcing;
3. 如果对象之间是一种普通的1:N的关联关系,则需要分析N端的对象的特征,而后进行判断它是否应该采用
Event Sourcing;如论坛中的帖子和回复,帖子与回复是1:N的关系,帖子可以没有回复,即帖子不关心它是否有回复;但是回复则不一样,回复一旦创建就只能关联这个帖子,它永远不可能再去关联其他帖子。
所以,从这个角度看,可以理解为回复是帖子的一部分,虽然帖子不关心它下面有多少个回复。所以,这种情况下,我们不应该对回复使用Event Sourcing,让回复被帖子内聚即可。所以与回复相关的操作都由帖子负责即可;再看另外一个例子:商品分类与商品,也是1:N的关系,但是他们的关系与帖子回复的关系不同,和帖子一样,商品分类不关心它下面是否有商品,另外商品也不关心它属于哪个分类,即便关心,商品所属的分类也可以调整;所以可以看出,商品分类没有聚合商品,商品也不会总是属于一个分类,商品的分类可能会改变;因此,可以得出,商品分类和商品都应该被独立跟踪,即都有采用Event Sourcing的必要;
所以,通过以上一些简单例子的分析,我们似乎可以找出一些规律,那就是:如果一个对象存在的意义只因为某个特定对象,并且其被创建时的出发点也是因为那个特定对象,那这个对象通常时需要被内聚在那个特定对象中,即这个对象不需要采用Event Sourcing机制。
另外,发现一个比较细微的差别是,以前我们在分析DDD的聚合的边界时,总是先找出聚合根,然后分析该聚合根应该内聚哪些实体;而现在我的思路是,直接从对象之间关系的双向角度,去分析每个对象是否有独立存在的意义。仔细想想,从思路上还是有些区别的。
所以,我认为我们还是要采用一种平和自然地心态去理解事物,分析其关系,不能一味的只采用DDD中聚合的这种结构去建模。如果采用DDD中那种聚合的思路去建模,你经常会发现,有些实体,在一些场景下是聚合内的一个子实体,而在另外一些场景下它又可以独立存在,以独立个体的方式与别的对象发生关系。这种情况下,会让你感觉非常别扭。实际上,这里的根本原因是你在尝试用一种只表示某种特定概念的聚合关系去表达所有其他的对象关系;正确的方法应该是,抛弃DDD中聚合概念的束缚,用一种开放平和的心态去分析和处理每一种对象关系,从关系双方的不同角度出发进行分析,分析它们对另一端对象的依赖程度和内聚程度,从而最终得出正确的设计;
[该贴被tangxuehua于2012-09-10 10:03修改过]