聚合
聚合逻辑上是一个整体
聚合内部用对象导航,将聚合的内容都取到内存中。
(什么是对象导航查询?
根据已经加载的对象,导航到它的关联对象 —— 2个对象之间存在关联关系。)
要用事务把聚合的操作保护起来。聚合决定了事务的最小边界。
外部不能直接修改非聚合根(由聚合根和聚合配合工厂或领域服务来负责)
非聚合根的构造器和setter为包级私有。
聚合根返回非根实体的列表时,需要转为不可变列表。
值对象
值对象不可变
(java里的String,LocalDateTime也是值对象)
值对象可以分为独立和依附于实体 2种。
martin fowler 用<> 代表值对象,是一种衍型。
实体之间采用关联来表达,实体和值对象之间的关系采用属性来表达。
泛化
继承只是泛化实现的一种方式,如果只是属性值不同导致的泛化,不适合采用继承
泛化的实现
数据库表的设计,有3种
每个类一个表 (可以采用共享主键,主键和外键是同一个。父类和子类是业务上是一个概念,采用共享主键是合理的)
只有子类有表
都放在一个大表里(反范式,不方便做非空约束,也容易混用字段,后期不易维护)
采用哪一个方式,根据差异属性多少和查询数据库性能综合得出
如果一个类是聚合根的子类,它的子类也是聚合根(TODO: 需要理解一下)
内存中的对象和数据库表的布局不一致,叫“阻抗不匹配”
如果将来多一个子类,就要改变父类或枚举定义,违反“开闭原则”。
父类只定义一个抽象方法,由子类去实现。
如果用JPA则没有必要使用DAO(因为DAO的事情被底层框架自动化了)
如果写代码时,发现用继承或接口实现都不合适,就应该反过来修改 领域模型。
限界上下文
一个限界上下文对应一套统一语言
每个子系统内部实现概念的严格一致性。(不同系统之间则没有必要一致)(让概念不一致的问题得到合理管控即可)
A上下文具有1个实体,B上下文也需要这个实体,A上下文的实体可以映射到B上下文中。
(上下文映射过程中,允许概念不一致,这是由不同关注点造成的)
限界上下文是一种解决大系统或大模型概念不一致的手段。
大模型拆分为不同小模型,每个小模型内部概念一致,这种小模型叫 限界上下文。
CQRS
Command要走领域模型
Query不走领域模型(直接SQL和DTO)
需要满足第三范式,不能违反传递依赖
命令模型需要遵循范式(数据冗余会造成数据不一致的风险)
查询模式鼓励反范式 (风险可控,不一致可以重新生成)
为了实现命令的查询仍然经过领域模型