设计模式:设计原则
闲言碎语
虽然几年前懵懵懂懂看完设计模式神书,可惜功力不够,无法透彻理解,也没有留下啥。现如今重拾神书,简述学习摘要,以便后续自己查阅。
它由罗伯特·C·马丁在21实际早期引入的面向对象编程和面向对象设计的六个基本原则。后面被应用到测试驱动领域、敏捷开发、自适应软件开发等中,做为它们的基本原则的重要组成部分。
另外,著名的 Gang of Four设计模式 为 “面对对象编程” 提供一套模拟现实世界关系的方法论,其中三大类、23种设计模式都是围绕着开篇的六大设计原则展开,都尽可能或多或少的契合六大原则中的几条。
如图:
设计模式的七大原则.png
简称为,SOLID(稳定的)
首先,认识下设计模式六大原则的英文表述和对应的中文意思:
Single Responsibility Principle:单一职责原则
Open Closed Principle:开闭原则
Liskov Substitution Principle:里氏替换原则
Law of Demeter:迪米特法则
Interface Segregation Principle:接口隔离原则
Dependence Inversion Principle:依赖倒置原则
把这六个原则的首字母联合起来(两个 L 算做一个)就是 SOLID (solid,稳定的),其代表的含义就是这六个原则结合使用的好处:建立稳定、灵活、健壮的设计。
六大核心原则
- 一、开闭原则,Open Closure Principle,OCP:描述抽象与实现的关系,可谓是六大原则之根本。
定义:软件实体(类、模块、函数等等)应该是可扩展的,但是不可修改的。
“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;
“闭”,是指对于原有代码的修改是封闭的,是不应该修改原有的代码。
OCP背后的主要机制是抽象和多态。
如何、何时抽象?
凭现有的实践经验预估将来合理的变化因素或者现实中遇到的变化因素,这时候就应该创建一种抽象来封装隔离变化它。
如何获得封闭性
1、抽象和多态获得显式封闭
2、使用“数据驱动”的方法获得封闭性,即多一个中间变量一切变得美好
100%的封闭是不现实且不可能做到的,应该进行的是有策略的封闭。
- 二、依赖倒置原则,Dependence Inversion Principle,DIP:框架设计的核心原则
定义:
1、高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
2、抽象不应该依赖于细节。细节应该依赖于抽象。
所谓的倒置,是从结构化程序设计过程而言。结构化程序设计,常常会导致顶层模块直接使用底层模块。
实现DIP手段是:采用面向接口、面向抽象编程。
层次化,Booch曾说过:“所有结构良好的面向对象架构都具有清晰地层次定义,每个层次通过一个定义良好、受控的接口,向外提供一组高内聚的服务。”
1、依赖于抽象设计,隔离程序的不稳定性。
2、依赖于接口设计,低层模块实现高层模块中的声明接口,并且被高层模块所调用。
应用DIP时候,我们发现往往是客户拥有抽象接口,它们的服务者则从这些抽象接口中派生。
- 三、单一职责原则,Single Responsibility Principle,SRP:规范单个类如何设计的基本原则,即类设计原则。
定义:一个类应该有且仅有一个引起它变化的原因。
何为职责?
一种引起类变化的原因,每一种职责都是类变化的轴线。
SRP强调类的高内聚性、低耦合、高复用。
高内聚要求模块化,模块化的手段即是拆分,拆分(横向拆分+纵向拆分)准则又是SRP。
- 四、迪米特原则(最少知道原则),loD,Law of Demeter:规范要求类与类、模块与模块之间的低耦合关联。
定义:一个对象应当对其他对象尽可能少的了解。
- 五、里氏替换原则,Liskov Substitution Principle,LSP:规范类继承关系,最佳继承层次。
定义:子类型(subtype)必须能够替换掉它的基类型(base type)
支持抽象和多态的关键机制之一即是继承。
1、违反LSP的场景常常也潜在违反OCP。
2、一个模型,如果独立地看,并不具有真正意义上的有效性。模型的有效性只能通过它的Client(具体使用场景)来验证。
3、LSP清晰指出,OOD中IS-A关系是就“行为方式”而言,而“行为方式”是可以被合理假设的,对象的“行为方式”才是软件真正关注的问题。
- 六、接口隔离原则,Interface Segregation Principle,ISP:规范接口设计原则,设计的接口应该具有高内聚、单一性、独立性。
定义:不应该强迫客户依赖于它们不用的方法。如果依赖于它们不使用的方法,则程序就面临着由于这些未使用方法的改变带来的变更。因此接口设计应该尽量细化接口,避免使用胖接口。
** OCP 和 LSP两个原则,规范类核心本质(抽象和多态、继承)的设计。 **
** SRP 和 loD两个原则,强调高内聚、低耦合设计。 **
** DIP 和 ISP两个原则,强调和规范面向接口设计。 **
以下补充原则
- 七、合成复用原则:组合优先,继承次之。
包的设计原则
以下六大原则中,前3个原则关注包的内聚性,指导我们对类进行组包;后3个关注包的耦合性,指导我们确定包与包之间的互相关系。
一、粒度,包内聚性原则,根据“自底向上”的观点对类进行划分
-
1、重用发布等价原则,Release Reuse Equivalency Principle ,REP
重用的粒度就是发布的粒度。任何可重用的软件实体必须同时是可被发布和可被跟踪的。
如果一个包中的软件是用来重用的,那么它就不能再包含不是为了重用目的而设计的软件。一个包中的软件要么都是可重用的,要么都不是可重用的。 -
2、共用重用原则,Common Resue Principle,CRP
一个包中的所有类应该是共同重用的。如果重用了包中的一个类,那么就要重用包中的所有类。
CRP告诉我们更多的是,什么类不应该放在一起。CRP规定互相之间没有紧密关联的类不应该在同一个包中。 -
3、共同封闭原则,Common Closure Principle,CCP
包中 所有类应该对于同一类性质的变化应该是共同封闭的。一个变化若对包产生影响,则将对包中所有的类产生影响。而对其它的包不造成影响。
这是单一职责SRP对于包的重新规定。同时该原则CCP适合开放封闭原则OCP密切关联。CCP原则的“封闭”和OCP中的“封闭”具有相同的含义。
一、稳定性:包的耦合性原则
- 1、无环依赖原则,Acyclic Dependencies Principle,ADP
在包的依赖关系图中不允许存在环。即包的依赖关系结构是一个有向无环图,DAG。
a、问题:每周构建问题(一周前4天各自开发,周五集中进行合成构建),集成往往会付出巨大大家,周六也要加班完成构建。
如何解决“每周构建”问题?
通过把开发环境划分成可发布的包。将开发人员使一个包可以工作时候,就把它发布给其他开发人员使用,并且赋予一个包一个版本号。其他开发人员将该版本的包引入自己目录中。包开发人员继续维护和开发新包,发布新版本。而包的使用者,则可以根据自己需要,决定是否更新包。
b、如何消除包之间依赖关系环。
1、使用依赖导致原则DIP。
2、将成环两个包中共同部分拆分除去形成一个新包,依赖新包。
2、稳定性依赖原则,Stable Dependencies Principle,SDP
朝着稳定的方向进行依赖。易变化包不应该依赖稳定包。
对于任何包而言,如果期望它是可变的,就不应该让一个难以更改的包依赖于它!否则,可变的包同样也会难以更改。
3、稳定抽象原则,Stable Abstract Principle,SAP
包的稳定程度和其抽象程度一致。朝着抽象方向扩展。