聚合是一个过程
聚合是一个过程,把紧密相连的实体、值对象,组合成一个更大的的实体、值对象,这个过程,就叫聚合(aggregation)。
一辆完整的小型家用汽车,由轮子、底盘、发动机、车架、方向盘、车灯等组成,发动机又由曲柄连杆机构、配气机构、冷却系、燃料供给系、润滑系、点火系、启动系等组成。
把曲柄连杆机构、配气机构等这些零件装配起来,形成一个完整的发动机,这个过程就叫做聚合。
把发动机、轮子等这些零件装配起来,形成一台完整的汽车,这个过程也叫聚合。
而DDD的本质是对真实物理世界的建模,DDD所提出的概念术语,都可以从现实世界中找到参照。
因此,聚合是一个过程,把紧密相连的实体、值对象,组合成一个更大的的实体、值对象,这个过程,就叫聚合(aggregation)。
聚合后的产物,可能是一个更大的实体,也可能是一个更大的值对象。
聚合是一把双刃剑
聚合是一把双刃剑,在键在于你如何使用。
试想一下,如果我们需要通过车子编号来查找一辆汽车,如果没有聚合,我们是不是得调用发起机实体获取发动机、调用底盘实体获取底盘、调用车架实体获取车架……,如果车子的零件越多,我们需要调用的实体就越多,这样子,就要求着我们必须要了解汽车的零件组成结构!
聚合可以达到屏蔽内部细节的目的。当汽车被做成聚合的时候,我们只需要将汽车编号传递给汽车聚合,就可以拿到汽车聚合对象,至于汽车聚合里面的发动机等零件是怎么装配到汽车聚合中的,这就是汽车聚合本身的职责了,我们无需关心。
又试想一下,如果需求是:获取某台汽车的发动机编号。
按照聚合的做法,得先获取到汽车这个实体,通过汽车这个实体才能获取到发动机实体,通过发动机实体才能获取到发动机编号。
这样的做法,在获取汽车实体的时候,同时将好多非关注的实体也获取到了,如车架、底盘等,造成程序运行性能极慢。
如果绕过汽车这个实体,直接取发动机这个实体,虽然性能会大幅度提升,但是这种做法有孛于实体,因为提供通过汽车编号获取发动机编号的行为方法,从物理世界上看,不应该是发动机实体需要提供的。
这种情况,可以通过领域服务来实现这种需求。
使用聚合的建议
1、聚合中的属性没有必要一次性全部加载到聚合中去,在需要用到的时候再加载聚合的具体属性。
比如汽车这个聚合,当需要获取发动机实体的时候,再执行加载发动机实体的逻辑。
public class Car {
// 车子编码
private String no;
// 发动机实体
private Engine engine;
// 底盘
private Chassis chassis;
// 获取发动机实体
public Engine engine() {
return EngineRepository.load(engineId);
}
}
2、聚合的粒度应该最小化
比如汽车,聚合的粒度最小化到汽车这个级别,不要聚合到汽车4S店这种级别。
3、没有必要,不要使用聚合,请使用领域服务