设计模式的五大设计原则与思想 SOLID
(SRP):单一职责原则 🐕🦺
1. 如何理解单一之原则 ❓
一个类只负责完成一个职责或功能,不要设计大而全的类,要设计粒度小,功能单一的类。单一职责原则是为了实现高内聚,低耦合,提高代码的复用性,可读性,可维护性
2. 如何判断类的职责是否足够单一❓
不同的场景,不同阶段的需求背景,不同的业务层面,对同一个类的职责是否单一,可能会有不同的判定结果。实际上,一些侧面的判断指标更具有指导意义和可执行性,比如,出现下面这些情况就有可能说明这类的设计不满足单一职责原则:
- 类中的代码行数,函数或者属性过多
- 类依赖的其他类过多,或者依赖类的其他类过多
- 私有方法过多
- 比较难给类起一个合适的名字
- 类中大量的方法都是集中操作类中的几个属性
3. 类的职责是否设计的越单一越好呢❓
单一职责原则通过避免设计大而全的类,避免将不想关的功能耦合在一起,来提高类的内聚性。同时,类职责单一,类依赖的和被依赖的其他类也会变少,减少了代码的耦合性 ,以此来实现代码的高内聚,低耦合。但是如何拆分的过细,实际上会适得其反,反而会降低内聚性。也会影响代码的可维护性
(OCP)开闭原则 ❎
1. 如何理解“对扩展开放,对修改关闭” ❓
添加一个新的功能,应该是通过在已有的代码基础上扩展代码(新增模块,类,方法,属性等),而非修改已有的代码的方式来完成。关于定义,我们有两点需要注意。第一点是,开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。第二点是,同样的代码改动,在粗粒度下,可能被认定“修改”;在细粒度下,可能又被认定为“扩展”。
2. 如何做到“对扩展开放,修改关闭”❓
我们要时刻具备扩展意识,抽象意识,封装意识。在写代码的时候,我们要多花点时间思考以下, 这段代码未来可能有哪些需求变更,如何设计代码结构,实现留好扩展点,一遍在未来需求变更的时候,在不改动代码整体接口,做到最小代码的改动下,将新的代码灵活的插入到扩展点上。
很多设计原则、设计思想、设计模式,都是以提高代码的扩展性为最终目的的。特别是 23 种经典设计模式,大部分都是为了解决代码的扩展性问题而总结出来的,都是以开闭原则为指导原则的。最常用来提高代码扩展性的方法有:多态、依赖注入、基于接口而非实现编程,以及大部分的设计模式(比如,装饰、策略、模板、职责链、状态)。
(LSP)里式替换原则 💱
里氏替换原则是用来指导,继承关系中子类如何设计的一个原则,立即里氏替换原则,最核心的就是理解“design by contract” 按照协议来设计 这几个字,父类定义了函数的“约定” ,那子类可以改变函数的内部实现逻辑,但是不能改变函数原来有的“约定”,这里的约定包括:函数声明实现的功能:对输入,输出,异常的约定;甚至包括注释中所罗列 的任何特殊说明
理解这个原则,我们还要弄明白里氏替换原则和多态的区别,虽然定义和描述代码实现上来看 ,多态和里氏替换原则类似,但他们关注的点不一样,多态是面向对象中的一大特征,也是面向对象编程语言的一种语法。它是一种代码实现的思路,而里氏替换原则是一种设计原则, 用来指导继承关系中子类该如何设计,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑及不破坏原有程序的正确性
(ISP)接口隔离原则 🧱
如何理解接口隔离原则 ❓
理解“接口隔离原则”的重点是理解其中的“接口” 两字,这里有三种不同的理解
如果把“接口” 理解为单个API 接口或者函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个粒度函数。
如果把“接口” 理解为OOP 中的接口,也可以理解为面向对象编程语言中的接口语法。那接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数
接口隔离原则与单一职责原则的区别 ❓
单一职责是针对类,模块,接口的设计,接口隔离原则相对于单一职责原则,一方面更侧重于接口的设计,另一方面它的思考角度也是不同的。接口隔离原则提供了一种判断接口的职责是否单一的标准,通过调用者如何使用接口来间接的判定。如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一
(DIP)依赖反转原则 💬
1. 控制反转 ❗
实际上,控制反转是一个比较笼统的设计思想,并不是一种具体的实现方式,一般是用来指导框架层面的设计。这里说的“控制” 指的是对程序执行流程的控制,而 “反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制,流程的控制权从程序员“反转”给了框架
2. 依赖注入❗
依赖注入和控制反转恰恰相反,它是一种具体的编码技巧,我们不通过new 的方式在内部创建依赖类的对象,而是将以来类对象在创建好之后,通过构造函数,函数参数等方式传递(或注入)给类来使用
3. 依赖注入框架❗
我们通过依赖注入框架提供的扩展点,简单配置一下所有需要的类及其与类之间依赖关系,就可以实现由框架在自动创建对象,管理对象的生命周期,依赖注入等原本需要程序员来做的事情。
4. 依赖反转原则❗
依赖反转原则也叫依赖倒置原则。 这条原则跟控制反转有点类似,主要是用来指导框架层面的设计。高层模块不依赖低层模块,他们共同依赖同一个抽象,抽象不需要依赖具体实现细节,具体实现细节依赖抽象。