底层逻辑的本质
创建型设计模式、结构型设计模式、行为型设计模式
设计模式的底层逻辑
1 设计模式的基石
面条型的代码、过程式的代码和面向对象的
类型 | 类比 雕刻诗文的修改 |
---|---|
面条型 | 一块木板雕刻一首诗;耦合太严重,牵一发而动全身 |
过程式 | 自顶向下,逐步求精;分而治之;每块木板上只雕刻一行诗;【极端情况全改】 |
面条型 | 诗由行组成,行由一个个字组成,活字印刷;复用性强 |
核心:洞察到事物的结构和关系,首先回答的是what,而不是how。过程式就是过分强调了how,一开始就思考怎么去做,过程式思维是以自己为中心,导演了整个功能流程,自己承担了太多自己不应该承担的职责,整个设计就显得不灵活。面向对象是从对象的角度去看问题,解决问题是由各个对象协作完成,设计模式的基石就是面向对象,脱离了面向对象去谈设计模式那是耍流氓。
2 设计模式的鼻祖
书籍:《设计模式:可复用面向对象软件的基础》,书中作者提到了一句话:“找到变化,封装变化”
,这才是设计模式的底层逻辑。
比如策略模式,具体的策略在变化;工厂模式,创建的对象在变化;模板模式,具体模板算法实现在变化……
3 再谈底层逻辑
“找到变化,封装变化”:什么在变化,如何封装变化。
三 设计模式要回答的两个问题
1 什么在变化
这里以对象生命周期的视角去看待对象的变化:创建,使用,消亡;
对象有三个不同维度的变化:对象结构的变化、对象规格的变化、对象行为的变化。
以对象结构变化为例,对象的关系划分成两类:
线性关系和非线性关系(树和图)。
在线性关系中,如何解决一个对象的变化不会影响到关联的对象?
在树型结构中,如何解决不断新增加对象的问题?
在图型结构中,如何解决用户方便使用复杂系统的问题?
找到变化是最为关键,不同的业务问题,遇到的变化问题也是不一样的,核心是要找到这些变化。比如对象规格的变化,有数量的变化、类型的变化、外观的变化,在实际编码的过程中就要有这种思考,比如创建一个对象,再深入思想下,有没有其它类型的对象?数量有没有变化?……只有找到了这些变化,具体怎么去封装变化就是技术的问题,接下来讨论如何封装变化。
2 如何封装变化
从封装的类型上看,有数据的封装、方法的封装、类型的封装等。就具体的封装方法而言,常见的有配置项、接口、抽象方法、类、注解、插件等具体的手段,再往上看主要使用了继承、组合的方法,再往上看封装的原则,常见的原则有单一职责、开闭原则、依赖倒置、隔离原则……要深入去思考什么在变化。
四 用底层逻辑推导结构型设计模式
1 寻找对象结构的变化
从UML看,对象之间的关系有依赖、泛化、组合、聚合,但就结构关系上看只有两种,线性关系和非线性关系(树、图)。
2 应对线性变化
两种方法:一种是通过增加适配来解决,另一种是通过代理来解决。
要点都是:一个对象不与变化的对象直接关联;引入第三方,第三方负责交互(降低依赖成本);
3 应对非线性变化
两种方法:一种是通过注册机制,另一种通过抽象层屏蔽复杂性(门面模式,在门面内把所有的复杂度都规避,对外提供简洁的接口)。
五 业务变化之道
设计模式还是要应用到实际的业务中才能发挥它的价值, Alan Shalloway 提到一个观点:无法预测哪里有变化,但能知道哪里可能有变化。
在做业务需求开发时,要有这种识别变化的意识,先不要陷入面向过程的思维中,不要一上来就考虑如何去实现,而是思考它是什么,会有哪些变化,比如对象的数量、对象的外观、对象的种类……当把这些思考清楚之后,才能设计得更合理。
六 对象设计之道
对象设计有三个问题:有哪些对象?对象之间的关系是怎样的?对象的职责有哪些?
当把这三个问题梳理清楚了,对象设计也就容易得多,也是面向对象分析与设计的核心。正常来讲,我们知道结构决定功能,功能决定行为,这是非常符合人的逻辑认识,但要想了解清楚对象的结构又是非常难的,就像新冠病毒的分子结构也不是那么容易破解的,尤其是复杂业务,它所包含的业务对象并不那么容易弄清楚它的结构。
我们可以反向思考,当有一种业务场景时,先思考它的职责是什么,再去思考应该由哪些业务对象去承担,这也是典型的归纳思维。比如在优惠券业务中,它的业务活动就三个:建券、发券、用券,也就是任何一个优惠券系统,它要提供这三个最为基础的能力,这三个能力又对应到两个业务对象:券批次和券实例,券批次相当于是券的模板,告知优惠券的预算有多少、券面额是多少、使用条件是什么……,具体发放到用户手上的才是券实例。
当有了业务对象之后,就要通过用例去思考对象模型的所包含的属性和方法有哪些,这个过程并不是一次就能完美完成的,而是通过多次打磨才行,这里面就要遵循一些原则,比如单一职责、开闭原则、依赖倒置的原则……,让整个模型的可扩展性更好。