参考:https://insights.thoughtworks.cn/backend-development-ddd/
战略设计: 更偏向于软件架构,得到限界上下文,拆分成多个微服务。
战术设计: 更偏向于编码实现。DDD战术设计的目的是使得业务能够从技术中分离并突显出来,让代码直接表达业务的本身,其中包含了聚合根、应用服务、资源库、工厂等概念。通常会应用设计模式。
关键原则:
聚合根的实现应该与框架无关:既然DDD讲求业务复杂度和技术复杂度的分离,那么作为业务主要载体的聚合根应该尽量少地引用技术框架级别的设施,最好是POJO
聚合根之间的引用通过ID完成:
聚合根内部的所有变更都必须通过聚合根完成:为了保证聚合根的一致性,同时避免聚合根内部逻辑向外泄露,客户方只能将整个聚合根作为统一调用入口
如果一个事务需要更新多个聚合根,首先思考一下自己的聚合根边界处理是否出了问题,因为在设计合理的情况下通常不会出现一个事务更新多个聚合根的场景。如果这种情况的确是业务所需,那么考虑引入消息机制和事件驱动架构,保证一个事务只更新一个聚合根,然后通过消息机制异步更新其他聚合根。
聚合根不应该引用基础设施。
外界不应该持有聚合根内部的数据结构。
尽量使用小聚合。
下图说明:不同的限界上下文,都可以有Product对象;
实体 VS 值对象:
实体: 实体对象表示的是具有一定生命周期并且拥有全局唯一标识(ID)的对象,比如本文中的Order
和Product
,
值对象:表示用于起描述性作用的,没有唯一标识的对象,比如Address
对象。
区分实体和值对象的一个很重要的原则便是根据相等性来判断
实体对象的相等性是通过ID来完成的,对于两个实体,如果他们的所有属性均相同,但是ID不同,那么他们依然两个不同的实体,就像一对长得一模一样的双胞胎,他们依然是两个不同的自然人。
值对象相等性的判断是通过属性字段来完成的。
数据库:值对象在数据库中跟实体的表放在一起:要么直接作为实体的属性,要么整体JSON格式作为实体属性
资源库(Repository)就是用来持久化聚合根的
不过DAO的设计初衷只是对数据库的一层很薄的封装,而Repository是更偏向于领域模型。另外,在所有的领域对象中,只有聚合根才“配得上”拥有Repository,而DAO没有这种约束