架构师训练营 -week02- 总结
第二周总结:
本周重点学习了面向对象的特点、设计模式、 领域驱动设计DDD里充血模型和贫血模型的区别,以及一个反应式编程框架 Flower 的设计案例分析。下面是本周的总结,结合了智慧老师的内容和小争哥的《设计模式之美》、还有四火老师《全栈工程师修炼指南》的内容。
面向对象
现在,主流的编程范式或者是编程风格有三种,它们分别是面向过程、面向对象和函数式编程。面向对象这种编程风格又是这其中最主流的。现在比较流行的编程语言大部分都是面向对象编程语言。大部分项目也都是基于面向对象编程风格开发的。面向对象编程因为其具有丰富的特性(有说封装/继承/多态三种特性,也有说封装/抽象/继承/多态四种特性的,主要是自己能理解并加以运用即可),可以实现很多复杂的设计思路,是很多设计原则、设计模式编码实现的基础。
设计原则
设计原则是指导我们代码设计的一些经验总结。设计原则这块儿的知识有一个非常大的特点,那就是这些原则听起来都比较抽象,定义描述都比较模糊,不同的人会有不同的解读。所以,如果单纯地去记忆定义,对于编程、设计能力的提高,意义并不大。对于每一种设计原则,我们需要掌握它的设计初衷,能解决哪些编程问题,有哪些应用场景。只有这样,我们才能在项目中灵活恰当地应用这些原则。
SOLID 原则 -SRP 单一职责原则
SOLID 原则 -OCP 开闭原则
SOLID 原则 -LSP 里式替换原则
SOLID 原则 -ISP 接口隔离原则
SOLID 原则 -DIP 依赖倒置原则
具体如下:
单一职责原则-SRP
又称为“内聚性原则”,即一个类,只执行一个职责,只能有一个引起它的变化的原因。
实现原则的关键:在做模型设计时,确定明确对象以及相关职责。
好处:增强系统的可移植性、健壮性。
开闭原则-OCP:
对修改是封闭的,对扩展是开放的。
实践原则的关键:抽象!
好处:增强了系统健壮性。
Liskov替换原则-LSP
子类型必须能够替换掉它们的基类型。例,父类为会飞的鸟,分别有麻雀、鸵鸟继承了这个父类, 那么对于鸵鸟来说,这个父类就是不适合的。
实现原则的关键:对于子类来说,父类的方法没有不适合的。
重构方向:抽取共性到基类;改成组合。
好处:符合OCP,增强系统的可扩展性、健壮性。
接口分离原则-ISP
不应该强迫客户程序依赖它们不需要的方法。
实现原则的关键:针对不同客户,切割出不同的接口类;针对不同的用户,对接口类实现并封装以适配不同的客户。
好处:系统接口发生变动时,不会影响所有客户。
依赖倒置原则-DIP:
高层模块不能依赖底层模块,而是大家都依赖于抽象。 抽象不能依赖于实现,而是实现依赖于抽象。
即先定义接口,再进行实现;高层模块不直接new底层模块,而是通过构造器注入、注解注入等方式将底层模块引入调用,并且要求高层模块定义注入的底层模块是其接口,在外部注入时,才将实际需要用到的实现类注入。
实现原则的关键:接口,依赖被动注入!
好处:增强了系统的可扩展性、可维护性与可测试性。
另外,还有DRY 原则、KISS 原则、YAGNI 原则、LOD 法则等等原则。
设计模式
设计模式是针对软件开发中经常遇到的一些设计问题,总结出来的一套解决方案或者设计思路。大部分设计模式要解决的都是代码的可扩展性问题。设计模式相对于设计原则来说,没有那么抽象,而且大部分都不难理解,代码实现也并不复杂。这一块的学习难点是了解它们都能解决哪些问题,掌握典型的应用场景,并且懂得不过度应用。
经典的设计模式有 23 种,它们又可以分为三大类:创建型、结构型、行为型。
创建型
常用的有:单例模式、工厂模式(工厂方法和抽象工厂)、建造者模式。
不常用的有:原型模式。
结构型
常用的有:代理模式、桥接模式、装饰者模式、适配器模式。
不常用的有:门面模式、组合模式、享元模式。
行为型
常用的有:观察者模式、模板模式、策略模式、职责链模式、迭代器模式、状态模式。
不常用的有:访问者模式、备忘录模式、命令模式、解释器模式、中介模式。
下图是面向对象、设计原则、设计模式、编程规范的关系图(摘自《设计模式之美》):
充血模型和贫血模型
最后说一下充血模型和贫血模型,近年来有一种更加被推崇的开发模式:基于充血模型的 DDD 开发模式。领域模型还有贫血和充血之说,其实是 Martin Fowler 造出来的概念。
要了解它们,得先知道这里讲的“血”是什么。这里的“血”,就是逻辑。它既包括我们最关心的业务逻辑,也包含非业务逻辑 。因此,贫血模型(Anemic Domain Model),意味着模型实体在设计和实现上,不包含或包含很少的逻辑。通常这种情况下,逻辑是被挪了出去,由其它单独的一层代码(比如这层代码是“Service”)来完成。严格说起来,贫血模型不是面向对象的,因为对象需要数据和逻辑的结合。这时的模型实体,不包含逻辑,但包含状态,而逻辑被解耦到了无状态 Service 中。这也是贫血模型反对者的重要观点之一。
再来了解一下充血模型(Rich Domain Model)。在充血模型的设计中,领域模型实体就是有血有肉的了,既包含数据,也包含逻辑,具备了更高程度的完备性和自恰性,并且,充血模型的设计才是真正面向对象的。
但是,目前几乎所有的业务后端系统,都是基于贫血模型的。可能的原因有以下三点:
第一,大部分情况下,我们开发的系统业务可能都比较简单,即便我们使用充血模型,那模型本身包含的业务逻辑也并不会很多,设计出来的领域模型也会比较单薄,跟贫血模型差不多,没有太大意义。
第二,充血模型的设计要比贫血模型更加有难度。因为充血模型是一种面向对象的编程风格。我们从一开始就要设计好针对数据要暴露哪些操作,定义哪些业务逻辑。而不是像贫血模型那样,我们只需要定义数据,之后有什么功能开发需求,我们就在 Service 层定义什么操作,不需要事先做太多设计。
第三,思维已固化,转型有成本。基于贫血模型的传统开发模式经历了这么多年,已经深得人心、习以为常。你随便问一个旁边的大龄同事,基本上他过往参与的所有 Web 项目应该都是基于这个开发模式的,而且也没有出过啥大问题。如果转向用充血模型、领域驱动设计,那势必有一定的学习成本、转型成本。很多人在没有遇到开发痛点的情况下,是不愿意做这件事情的。
所以说,基于贫血模型的传统的开发模式,比较适合业务比较简单的系统开发。相对应的,基于充血模型的 DDD 开发模式,更适合业务复杂的系统开发。比如,包含各种利息计算模型、还款模型等复杂业务的金融系统。
最后有几章比较好的相关性文章,可以作为延展阅读和学习,都是极客时间里的专栏:
https://time.geekbang.org/column/article/160991
https://time.geekbang.org/column/article/141679
https://time.geekbang.org/column/article/169600
评论