设计模式总篇:从为什么需要原则到实际落地(附知识图谱)
聊聊为什么需要`原则`
我们所有人都看过科幻电影,都看到过未来场景中人类和机器人和平相处的场景
为了让拥有自主智能
的机器人不失控,人类为机器人制定了三大定律:
<font color="red">第一定律:机器人不得伤害人类个体,或者目睹人类个体将遭受危险而袖手不管</font>
<font color="red">第二定律:机器人必须服从人给予它的命令,当该命令与第一定律冲突时例外</font>
<font color="red">第三定律:机器人在不违反第一、第二定律的情况下要尽可能保护自己的生存</font>
当然有时也会出现下面的情况,机器人和人类开始互为阵营,各自为敌
但是各自为敌的情况出现,一般都是机器人觉醒了自我意识,不再遵守三大定律
从逻辑学来说,如果机器人完全遵守三大定律及其衍生的条约
,那么机器人就可以和人类和平相处,当然也会有意外发生。
写代码为什么需要设计原则
和机器人的三大定律
相仿,几十年的编程经验,让几代人总结出来了一些代码设计上的定律
,这就是设计模式的七大原则
*我们遵循七大原则,一定会写出最完美的代码吗?*
答案当然是不一定,毕竟没有人能保证自己可以完全遵循七大原则,同时个人的编程能力也会起到决定性因素。
*那我们为什么还要遵守?*
我自己想到的一句名言(以后或许可以成为名言~)
向着最好的方向去努力,总不会是最差的结果。
七大原则详解
开闭原则 ★★★★★
软件实体对扩展是开放的,但对修改是关闭的,即在不修改一个软件实体的基础上去扩展其功能
*例如:*
以策略模式为例,当我们新增一种策略的时候,只需要实现策略顶层接口,在调用的时指向新的策略即可
针对这一条原则,在实现难度上要比单一职责更难,在编码期间,我们需要充分考虑未来的拓展性,规范接口,依赖抽象,这样才能在需要拓展的时候,非常方便的实现其效果
最佳实践案例:【一起学系列】之模板方法:写SSO我只要5分钟
说明:在接入第三方SSO时,如果需要新增接入方,基于文中的案例,只需实现固定接口,即可优雅的实现相应需求
依赖倒置原则 ★★★★★
要针对抽象层编程,而不要针对具体类编程
*例如:*
以适配器模式为例,将一个类的接口转换成客户希望的另外一个接口,以此实现的前提便是代码中所依赖的都是抽象的,因为只有依赖抽象,才能在代码运行期间改变其实体,利用多态
实现需要的效果
针对该条原则,其实有一定编程经验的人一定会在无形中注意到,而且了解设计模式的话,会发现所有涉及接口和实现的设计模式都会遵从这一条原则
最佳实践案例:【一起学系列】之模板方法:写SSO我只要5分钟
说明:和上一条原则的侧重点不同,在SSO中必然有其固定的流程,如登录-获取Token-获取用户信息-解析-退出等等,在代码的编写阶段,需要我们定义出接口/抽象类,然后依赖于抽象层,最终改变具体类,以此达到无缝切换的效果
合成复用原则 ★★★★☆
总结一句话就是:多用组合,少用继承
*例如:*
以单例模式和代理模式为例,它们都是该模式的最佳实践者,单例模式是把不同的策略接口通过组合
的方式嵌入到Context
类中,如代码所示:
同理,代理模式也是如此,这里就考虑到一个问题,为什么要多用组合而非继承?
其实还是Java中单继承引发的问题,同时继承的语义
过于苛刻,因此更多的时候建议善用组合
最佳实践案例:【一起学系列】之策略模式:好多鸭子啊
说明:策略模式就是合成复用原则的最佳实践者,没有之一
单一职责原则 ★★★★☆
类的职责要单一,不能将太多的职责放在一个类中
*例如:*
在代码设计中某种场景可能存在多种不同的状态,很可能就把代码混在一起了,这时我们利用状态模式
进行设计,把各种状态对应的实现细节都用类的级别单独划分,即体现了单一职则原则
针对这一条原则,其实绝大多数人在设计之初都会考虑到,但问题就在于随着工作中人员职责的交叉,很有可能会破坏他人设计的最初目的,为了方便,让一个类拥有五花八门的功能
最佳实践案例:【一起学系列】之状态模式:你听过“流程”模式吗?
说明:在状态模式中,每一种状态的处理都是独立的一个类,每个类只需要处理自身的核心逻辑,完美体现了单一职责原则
里氏代换原则 ★★★★☆
在软件系统中,一个可以接受基类对象的地方必然可以接受一个子类对象
当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法
继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义
*例如:*
我们都用过ArrayList
,有谁看过 forEach
方法的源码?
ArrayList
重写的方法:
我们看到,ArrayList
的重写只是针对数组这种结构优化了性能,其目的性和Iterable
接口中的完全一致,因此这种方式的重写不会引起任何问题,反而可以提高效率,我们需要学习这样的方式
迪米特原则 ★★★☆☆
一个对象应该对其他对象保持最少的了解,又名:最少知道原则
*例如:*
在代码设计场景中,某一个类的调用都会固定使用三个方法,是否可以考虑把三个方法抽取出来,提供一个公共的对外方法?这种思路就是外观模式
,外观模式也是迪米特原则的最佳实践
最佳实践案例:【一起学系列】之适配器模式:还有外观模式呢
说明:利用外观模式
构建统一的对外方法,屏蔽其内部实现,这样一旦内部实现需要更改,完全不会影响调用方,你Get了吗?
接口隔离原则 ★★☆☆☆
使用多个专门的接口来取代一个统一的接口
这个模式其实也很好理解,比如我们定义了接口A,接口B实现了接口A,接口C实现了接口B,基类D其实只需要接口C的方法,但是此时不得不实现所有的方法
<font color="red">其实造成这个根本原因:对接口的抽象,设计出现了偏差</font>
毕竟看过JDK源码或者Spring源码的同学,可以经常发现某一个接口可能实现了一大堆的接口,但是对于普通开发者而言,没有这种强大的设计能力,就需要在设计的时候多思考,如果发现违背了接口隔离原则
的情况,就应该对接口进行拆分
思维导图
Processon分享地址:https://www.processon.com/view/link/5f0210aa7d9c0844204b4845
>
PS:需要源文件的小伙伴可以在文末扫描二维码,发送【设计模式】即可
设计模式的系列文章推荐
| 所属类型 | 设计模式 | 标题 & 链接 |
| ------------------------------------- | ------------------------------------ | ------------------------------------------------------------ |
| <font color="red">行为型模式</font> | 策略模式 | 【一起学系列】之策略模式:好多鸭子啊 |
| <font color="red">行为型模式</font> | 观察者模式 | 【一起学系列】之观察者模式:我没有在监控你啊 |
| <font color="red">行为型模式</font> | 命令模式 | 【一起学系列】之命令模式:封装一个简单Jedis? |
| <font color="red">行为型模式</font> | 模板方法模式 | 【一起学系列】之模板方法:写SSO我只要5分钟 |
| <font color="red">行为型模式</font> | 迭代器模式 | 【一起学系列】之迭代器&组合:虽然有点用不上啦 |
| <font color="red">行为型模式</font> | 状态模式 | 【一起学系列】之状态模式:你听过“流程”模式吗? |
| <font color="red">行为型模式</font> | 职责链模式 | 【一起学系列】之剩下的设计模式们 |
| <font color="red">行为型模式</font> | 备忘录模式 | 【一起学系列】之剩下的设计模式们 |
| <font color="blue">结构型模式</font> | 装饰器模式 | 【一起学系列】之装饰器模式:不改代码增强功能? |
| <font color="blue">结构型模式</font> | 适配器模式 & 外观模式 | 【一起学系列】之适配器模式:还有外观模式呢 |
| <font color="blue">结构型模式</font> | 组合模式 | 【一起学系列】之迭代器&组合:虽然有点用不上啦 |
| <font color="blue">结构型模式</font> | 代理模式 | 【一起学系列】之代理模式:是为了控制访问啊! |
| <font color="green">创建型模式</font> | 工厂模式<br />(工厂方法及抽象工厂) | 【一起学系列】之工厂模式:产品?产品族? |
| <font color="green">创建型模式</font> | 单例模式 | 【一起学系列】之单例模式:只推荐三种~ |
| <font color="green">创建型模式</font> | 建造者模式 | 【一起学系列】之剩下的设计模式们 |
源码链接
兼顾了《HeadFirst》以及《GOF》两本经典书籍中的案例
提供了友好的阅读指导
版权声明: 本文为 InfoQ 作者【Kerwin】的原创文章。
原文链接:【http://xie.infoq.cn/article/9123383471debf2bd6098435d】。文章转载请联系作者。
评论