DDD入门学习(源自阿里&美团博客)

理论

Domain Primitive(DP)

  • 原则一:Making implicit concepts explicit,让隐性概念显性化。假设酒店入住人姓名是一个String类型字段,但我们可以将姓名的概念显性化,编写一个名为Name的Value Object来描述姓名,其中能将姓名拆分成姓和名,还能够支持国际化。

  • 原则二:Making implicit concepts explicit,让隐性上下文显性化。假设酒店支付200元,200元不仅表示200,还包含币种上下文,我们可以编写一个名为Money的Value Object来描述金额,其中包含金额和币种。

  • 原则三:Encapsulate Multi-Object behavior,封装多个对象的行为。假设现币种是人民币,但酒店仅支持美元支付,那么需要将人民币按照当前汇率换算成美元进行支付,这部分逻辑不适合放在Money对象中,但零散在外部也不合适;该功能涉及两个Money,一个汇率,汇率来源于外部接口,需要输入源币种和目标币种获取汇率;已知源币种、目标币种,然后获取汇率,可以设计一个ExchangeRate的Value Object来存放源币种、目标币种和接口返回的汇率,该对象内部提供币种换算功能,这样币种换算的功能就能内聚到ExchangeRate中,而ExchangeRate通过接口返回值构造,非常简洁。

Domian Primitive是一个在特定领域里,拥有精准定义的、可自我验证的、拥有行为的Value Object,其value应具有不可变特性。相比DDD中的值对象,Domain Primitive更强调具有完整的定义与描述,而不是零碎的值组成。

DDD相关名词

  • 贫血模型:实体对象仅用于表示数据源数据的映射,只有属性没有行为,业务逻辑分散在不同的service、controller中。贫血模型特征包括:1. 存在大量FooDo对象但仅用于表示数据映射;2. service和controller中有大量业务逻辑如校验、计算、格式转换、数据映射;3. 大量且重复的Utils工具类。

  • 实体:由特定标识如ID(非属性)区分的对象。

  • 值对象:由属性描述,不存在唯一标识的对象。

  • 聚合根:

  • 领域服务

  • 领域

  • 限界上下文

驱动流程

DDD领域驱动设计,如何体现到编码流程层面呢?在编写服务前,我们会先定义好接口契约,双方做好约定;在编写具有抽象通用的服务时,我们会先编写接口再编写接口的具体实现类。

DDD同理,在先决工作完成后进入代码开发阶段,按照抽象出的领域,编写领域中包含的实体、值对象、领域服务类,这些对象高度内聚,且定义明确,只关注领域内的业务,不强依赖于外部数据源和框架;接下来进行服务的编排,定义好服务接口;最后是实现接口,并做好防腐处理,同时领域对象也能起到一部分防腐作用,两者共同形成架构的ACL。

可以参考的规范

  • Repository接口位于domain层,其实现类位于infrastructure层;Repository接口中方法理应名为find/save/remove,避免直接命名select/insert/update/delete,因为domain层不应该感知数据源是DB或者是其他,从而屏蔽domian层对DB的感知。

常见误区

  • DDD是一种思想,并非条条框框,也不是一个固定的架构。

  • 并不是对象叫FooDo就能称作领域实体,实体需要具备与自己相关的业务逻辑。

常见问题

  • 某个查询仅需要表中的部分字段,DO是表的全映射,且Repository接口入参与出参只与聚合根或实体打交道,那么每次查询都会查出表中所有值,增加了开销。目前做法是POJO作为表全映射,DO跟随业务需求,通过converter还原成聚合根或者实体,这样做会导致DO和converter方法较多。

未完待续……

参考文章

阿里技术专家详解 DDD 系列 第一讲- Domain Primitive - 知乎 (zhihu.com)

你可能感兴趣的:(后端,学习,DDD,领域驱动设计,java)