设计模式学习笔记
七大原则
一、开闭原则(Open Closed Principle ,OCP)
含义
当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。
作用
- 测试时只需要对拓展的代码进行测试
- 提高代码的复用性
- 提高软件的可维护性
二、里氏替换原则(Liskov Substitution Principle,LSP)
定义
继承必须确保超类所拥有的性质在子类中仍然成立。–> 子类可以扩展父类的功能,但不能改变父类原有的功能
里氏替换原是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。
总结
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
- 子类中可以增加自己特有的方法
- 当子类的方法重载父类的方法时,方法的输入参数要比父类的方法更宽松
- 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的的返回值要比父类的方法更严格或相等
修正
如果程序违背了里氏替换原则,则继承类的对象在基类出现的地方会出现运行错误。这时其修正方法是:取消原来的继承关系,重新设计它们之间的关系
例子
“正方形不是长方形”、“几维鸟不是鸟”
作用
- 里氏替换原则是实现开闭原则的重要方式之一
- 克服了继承中重写父类造成的可复用性变差的缺点。
- 类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性
三、依赖倒置原则(Dependence Inversion Principle,DIP)
定义
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象
目的
依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性
核心思想
要面向接口编程,不要面向实现编程
作用
依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
- 依赖倒置原则可以降低类间的耦合性。
- 依赖倒置原则可以提高系统的稳定性。
- 依赖倒置原则可以减少并行开发引起的风险。
- 依赖倒置原则可以提高代码的可读性和可维护性。
实现方法
使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。
- 每个类尽量提供接口或抽象类,或者两者都具备
- 变量的声明类型尽量是接口或者是抽象类。
- 任何类都不应该从具体类派生。
- 使用继承时尽量遵循里氏替换原则。
四、单一职责原则(Single Responsibility Principle,SRP)----单一功能原则
定义
对象不应该承担太多职责,如果一个对象承担了太多的职责,至少存在以下两个缺点:
- 一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力;
- 当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。
核心
控制类的粒度大小、将对象解耦、提高其内聚性
优点
- 降低类的复杂度。一个类只负责一项职。
- 提高类的可读性
- 提高系统的可维护性
- 变更引起的风险降低
实现
发现类的不同职责并将其分离,再封装到不同的类或模块中
五、接口隔离原则(Interface Segregation Principle,ISP)
定义
要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
与单一职责原则的不异同
相同点
* 提高类的内聚性
* 降低类之间的耦合性
* 体现封装的思想
不同点
- 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离
- 单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。
优点
约束接口、降低类对接口的依赖性
- 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
- 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。
- 如果接口的粒度大小定义合理,能够保证系统的稳定性;但是,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险。
- 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。
- 能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。
实现方法
- 接口尽量小,但是要有限度。—> 一个接口只服务于一个子模块或业务逻辑。
- 为依赖接口的类定制服务。—> 只提供调用者需要的方法,屏蔽不需要的方法。
- 了解环境,拒绝盲从。
- 提高内聚,减少对外交互。
六、迪米特法则(Law of Demeter,LoD)----- 最少知识原则(Least Knowledge Principle,LKP)
定义
如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用
目的
减低类的耦合,提高模块的独立性
实现
-
从依赖者的角度来说,只依赖应该依赖的对象。
-
从被依赖者的角度说,只暴露应该暴露的方法。
注意事项
-
在类的划分上,应该创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。
-
在类的结构设计上,尽量降低类成员的访问权限。
-
在类的设计上,优先考虑将一个类设置成不变类。
-
在对其他类的引用上,将引用其他对象的次数降到最低。
-
不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。
-
谨慎使用序列化(Serializable)功能。
合成复用原则(Composite Reuse Principle,CRP)—组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)
含义
软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现
如果要使用继承关系,则必须严格遵循里氏替换原则