基础概念:Domain Primitive(DP/原子领域)
就好像Integer、String是所有编程语言的Primitive一样,DP是 DDD的 原子类型、基础类型
在DDD里,DP可以说是一切模型、方法、架构的基础,就像Integer、String一样,DP在DDD里,又是无所不在的。
DP的定义
Domain Primitive (DP)是一个在特定领域里,拥有精准定义的、可自我验证的、拥有行为的 Value Object 。
- DP是一个传统意义上的Value Object,拥有Immutable的特性
- DP是一个完整的概念整体,拥有精准定义
- DP使用业务域中的原生语言
- DP可以是业务域的最小组成部分、也可以构建复杂组合
什么情况下应该用Domain Primitive
常见的DP的使用场景包括:
- 有格式限制的
String
:比如Name
,PhoneNumber
,OrderNumber
,ZipCode
,Address
等 - 有限制的
Integer
:比如OrderId
(>0),Percentage
(0-100%),Quantity
(>=0)等 - 可枚举的
int
:比如Status
(一般不用Enum因为反序列化问题) Double
或BigDecimal
:一般用到的Double
或BigDecimal
都是有业务含义的,比如Temperature
、Money
、Amount
、ExchangeRate
、Rating
等- 复杂的数据结构:比如
Map>
等,尽量能把Map
的所有操作包装掉,仅暴露必要行为
DP三原则
- 将隐性的概念显性化。
- 将 隐性的 上下文 显性化
- 封装 多对象 行为
案例
使用DDD进行应用架构
一个好的应用架构,应该需要实现以下几个目标:
- 独立于框架:架构不应该依赖某个外部的库或框架,不应该被框架的结构所束缚。
- 独立于UI:前台展示的样式可能会随时发生变化(今天可能是网页、明天可能变成console、后天是独立app),但是底层架构不应该随之而变化。
- 独立于底层数据源:无论今天你用MySQL、Oracle还是MongoDB、CouchDB,甚至使用文件系统,软件架构不应该因为不同的底层数据储存方式而产生巨大改变。
- 独立于外部依赖:无论外部依赖如何变更、升级,业务的核心逻辑不应该随之而大幅变化。
- 可测试:无论外部依赖了什么数据库、硬件、UI或者服务,业务的逻辑应该都能够快速被验证正确性。
防腐层
这种常见的设计模式叫做Anti-Corruption Layer(防腐层或ACL)。
很多时候我们的系统会去依赖其他的系统,而被依赖的系统可能包含不合理的数据结构、API、协议或技术实现,如果对外部系统强依赖,会导致我们的系统被”腐蚀“。
这个时候,通过在系统间加入一个防腐层,能够有效的隔离外部依赖和内部逻辑,无论外部如何变更,内部代码可以尽可能的保持不变。
ACL不仅仅只是多了一层调用,在实际开发中ACL能够提供更多强大的功能:
- 适配器:很多时候外部依赖的数据、接口和协议并不符合内部规范,通过适配器模式,可以将数据转化逻辑封装到ACL内部,降低对业务代码的侵入。在这个案例里,我们通过封装了ExchangeRate和Currency对象,转化了对方的入参和出参,让入参出参更符合我们的标准。
- 缓存:对于频繁调用且数据变更不频繁的外部依赖,通过在ACL里嵌入缓存逻辑,能够有效的降低对于外部依赖的请求压力。同时,很多时候缓存逻辑是写在业务代码里的,通过将缓存逻辑嵌入ACL,能够降低业务代码的复杂度。
- 兜底:如果外部依赖的稳定性较差,一个能够有效提升我们系统稳定性的策略是通过ACL起到兜底的作用,比如当外部依赖出问题后,返回最近一次成功的缓存或业务兜底数据。这种兜底逻辑一般都比较复杂,如果散落在核心业务代码中会很难维护,通过集中在ACL中,更加容易被测试和修改。
- 易于测试:类似于之前的Repository,ACL的接口类能够很容易的实现Mock或Stub,以便于单元测试。
- 功能开关:有些时候我们希望能在某些场景下开放或关闭某个接口的功能,或者让某个接口返回一个特定的值,我们可以在ACL配置功能开关来实现,而不会对真实业务代码造成影响。同时,使用功能开关也能让我们容易的实现Monkey测试,而不需要真正物理性的关闭外部依赖。
抽象数据存储层
抽象第三方服务
抽象中间件
个人理解
目前个人理解就是将一些可封装成DP的数据类型,封装成DP,在DP内完成对数据的强校验,错误处理,提高在入参时的清晰度,最终实现降低业务代码的耦合度,提高可测性,做到一次修改DP模型内的校验,定义,在逻辑发生改变时,在DP模型内进行修改即可。
在应用层面,就是面向接口编程,尽量实现不耦合强依赖某个实现,可灵活替换底层实现。通常加入防腐层设计模式实现依赖解耦。