设计模式概述
简单介绍什么是设计模式,以及设计模式的 7 大原则
为什么需要设计模式?
套用树人哥的一句话:其实世上本没有设计模式,走的人多了就有了设计模式。
本来大家都是按照自己的方式写代码,然后根据不同需求,写出各种可扩展的、可维护的代码。然后,1995 年,GoF 四个人就将这些经验性代码总结出来,汇总成 23 种编程范式。
其实就是编程的最佳实践,针对这种问题你就得这么干,因为根据历史经验来看,这么干是最优的。
设计模式的本质是面向对象设计原则的实际应用。
0x00 设计模式分类
按目的来分
- 创建型:用于描述如何创建对象,将对象的创建与使用分离开
- 结构型:用于描述如何将类或对象按照某种布局组成更大的结构(类似于聚合)
- 行为型:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务(类似于组合)
按作用范围来分
- 类模式:用于描述类与子类的关系,是静态的,在编译时就能确定下来(通过继承实现)
- 对象模式:用于描述对象之间的关系,在运行时刻是变化的(通过聚合/组合实现)
范围\目的 | 创建型 | 结构型 | 行为型 |
---|---|---|---|
类模式 | 工厂方法 | 适配器(类) | 模板方法、解释器 |
对象模式 | 单例、原型、抽象工厂、建造者 | 代理、适配器(对象)、桥接、装饰、外观、享元、组合 | 策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录 |
0x01 Prin 1:开闭原则
Software entities should be open for extension, but closed for modification.
- 需求变更的时候,尽量通过扩展来实现需求,而不是通过修改源码来实现。
- 开闭原则是面向对象程序设计的终极目标
- 实现方法:通过抽象约束、封装变化来实现开闭原则,即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在具体实现类中。
0x02 Prin 2:里氏替换原则
Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.
- 把父类都换成子类,代码的行为不会发生改变。
- 里氏替换原则是针对继承提出的原则:什么时候应该使用继承,什么时候不应该使用继承?
- 里氏替换原则是实现开闭原则的重要方式之一
- 克服了继承中重用父类造成的可用性变差的问题
- 实现方法:子类继承父类时,可以增加新的方法,不要重写父类的方法(如果重写了父类方法,在多态的情况下,不会出现期望的结果)
0x03 Prin 3:依赖倒置原则
High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions.
- 核心思想:面向接口编程,不要面向实现编程
- 依赖倒置原则是实现开闭原则的重要方式之一,它降低了 Client 与具体实现之间的耦合
- 侧重点是层(类)与层(类)之间的解藕
- 实现方法:每个类尽量提供接口或者抽象类、任何类都不应该从具体类派生、继承时尽量遵循里氏替换原则
- 比如说 a 领导带领了 b 下属,这里 a 依赖于 b,此时又来了一个下属 c,然后 a 在分配任务的时候需要判断一下需要分给谁,如果再来一个下属 d,还需要再增加一个判断。这样显然很麻烦。这时我们抽象一个 a1,a 只把任务分配给 a1,即 a 依赖于 a1,b、c、d 继承 a1 实现具体的操作。这个就是依赖倒置了,倒置到需要依赖的类的抽象父类了。
- 依赖注入其实就是不在类内初始化对象(领导不直接询问下属的工作,而是通过 a1 提供给他),依赖注入是控制反转的实现方式,控制反转是依赖倒置的实现方式。
0x04 Prin 4:单一职责原则
There should never be more than one reason for a class to change.
- 核心思想:引起类变化的原因有且仅有一个,这一个原因就是表示单一职责
- 实现方法:接口划分的粒度问题,根据具体业务的不同而变化。没有最好,只有最合适。
0x05 Prin 5:接口隔离原则
Clients should not be forced to depend on methods they do not use.
- 关注点是接口依赖程度的隔离,Client 不应该被迫依赖于它不需要的方法
- 实现方法:缩小接口囊括的方法,接口设计里面没有银弹
0x06 Prin 6:迪米特法则
Talk only to your immediate friends and not to strangers.
- 核心思想:两个软件实体如果不需要直接交互,那么就不应该发生直接的相互调用,可以通过第三方转发调用。目的是降低类之间的耦合。
- 滥用迪米特法则会导致系统出现大量中间类,降低通信效率,所以凡事都有个度
0x07 Prin 7:合成复用原则
- 核心思想:在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系实现。
- 实现方法:一个对象通过包含一个已有对象成为一个新对象(聚合 or 组合)
参考:
📌 软件设计模式概述