「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」
计划:
- 通过DDD架构的设计来引出设计模式,再从设计模式的学习反馈到DDD
DDD架构图:
www.processon.com/view/link/6…
几个思想:
-
相关的代码放在一个地方
-
已有的代码尽可能地复用而不是修改
-
尽可能地不将不必要的信息泄露给外部
- eg:在调用一个返回list的接口时,如非必要,我们是不会介意返回的是哪种list的
领域内聚的基础 - 聚合
- 通过内聚领域的组合做业务脚本,尽可能地达到对扩展开放,对修改封闭
需要思考的几个问题:
- 组合模式和外观模式有什么区别?
【题外话】 其实从某种程度上来说,这篇文章说得很对:juejin.cn/post/702402… DDD落地最大的关键就在于将每一层尽可能地做成可插拔、和接口强相关的而不必关心其他层的实现细节实现解耦,[可以看阿里出的那几期DDD落地的,其实做的就是这么件事情],那么各个层之间的独立变更就不会互相影响,而如果将设计模式以及相关原则贯彻在编码规范中,其实这些东西就是必要的了。可以这么说:DDD落地这一命题,在很多情况下做的无非就是作为一个包括了多种设计模式的编码规范的落地,促进团队代码的健壮性,降低后续维护成本,增强代码可重用性,减少事务脚本类型的代码。
第一类 - 创建型模式
引入创建型模式的原因,一般是:
- 将信息形式转换的行为做一个封装,使这些信息转换可达成内聚以及统一管理
- 减少外部对于信息转换时所需要的额外知识(例如:构造函数到builder;从构造函数到抽象工厂),方便信息的内聚
-
信息的隐藏 - 工厂模式
- 通过对上层提供 抽象类的实现,屏蔽底层对抽象类区别的实现
-
对象的构造 - builder生成器模式/原型模式
-
生成器模式的一大弊病是:
- 相比直接调用构造函数,多了一个builder对象的内存占用,而这是非必要的
但builder有一个优点,是:我们对于该对象的构建就可以基于外部已知的数据进行了(在外部知道核心内容的时候),而不必对外提供多种不知道是什么的参数。
-
原型模式 - 依赖clone方法的实现深浅拷贝
- 一般来说,我们会使用不同的对象来进行同一份信息的不同方式的存取,那么我们一般会使用属性转换来进行数据之间信息的流转。
-
单例模式 - DDD中一般很少会使用到单例模式,除非是在一些很重要的共享节点上,需要实现状态共享,或者数据的记录。
- 一般面试会借助单例模式,询问饿汉和懒汉,来询问多线程相关的信息。
-
第二类 - 结构型模式
引入结构型设计模式的原因,一般是:
- 降低业务代码之间的耦合,降低业务代码的复杂程度
- 使得更低级的概念得以内聚,例如数据库连接、外部连接
- 低级概念可以更容易地组装复用成新的业务逻辑
-
DCL层的理论基础 - 适配器模式
-
DCL层一般翻译为防腐层。
-
代码中引入适配器的原因,一般都是:
-
内外部信息的不一致,比如:
- 和第三方交互,第三方的入参对象,和当前系统对应的入参对象字段不一致。
那么,我们会引入一个适配器,来解决这个问题,并且在全局使用这个适配器,来减少我们原有业务逻辑代码之中对于外部信息的引入。
-
-
-
专业交付 - 桥接模式
- 桥接模式一般是在解决信息聚合的复杂程度过高时引入的。
- 这可以使得我们重新思考抽象,通过持有对象的方式,来降低不同概念之间的耦合关系,降低代码的复杂性。
- 装饰模式
- 见娃套娃
-
外观模式
-
外观模式也成为门面模式,其实就是:
-
通过封装一个聚合了多个基础类的类,使得外部对于这些类的调用,变成对这个聚合类的调用。
-
好处就是
- 外部不需要知道这些聚合类是如何相互交互的;
- 基础类的交互就放到聚合类里面了,使得基础的流程被拼接起来,变成了一个完整的方式。
-
-
-
享元模式
享元模式在DDD中,在DDD的底层做cache的时候,会有一些用处,但并不是常见的处理方式。
-
代理模式
代理模式就属于很硬的设计模式了,在各种中间件中非常常见。
\