七个面向对象设计原则

单一职责原则:一个对象应该只包含单一的职责,并且该职责被完整的封装在一个类中。

开闭原则:软件实体应该对扩展开放,对修改关闭。

里氏代换原则:所有引用基类的地方必须能透明地使用其之类的对象

依赖倒转原则:高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。

接口隔离原则:客户端不应该依赖那些他不需要的接口

合成复用原则:优先使用对象组合。而不是通过继承来达到复用的目的。

迪米特原则:每一个软件单位对其他单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。

单一职责原则

单一职责原则用于控制类的粒度大小。

定义:一个对象应该只包含单一的职责,并且该职责被完整的封装在一个类里。

另一个定义:就一个类而言,应该仅有一个引起它变化的原因。

开闭原则

定义:软件实体应当对扩展开放,对修改关闭。

软件实体可以指一个软件模块,一个由多个类组成的局部结构或一个独立的类。

开闭原则就是指软件实体应尽量在不修改原有代码的情况下进行扩展。

抽象化是开闭原则的关键。

可以定义一个相对稳定的抽象层,而将不同实现行为移至具体的实现层中完成。

里氏代换原则

定义:所有引用基类的地方必须能透明地使用其子类的对象。

里氏代换原则表明,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误或者异常,反过来则不成立,如果一个软件实体使用的是一个子类的对象,那么它不一定能够使用基类对象。

在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

在运用里氏代换原则时应该将父类设计成抽象类或者接口,让子类继承父类或实现父类接口,并实现在父类中声明的方法。

里氏代换原则的本质是 “子类不能破坏父类的契约”,其核心价值是保证继承关系的安全性和代码的可维护性。

依赖倒转原则

定义:高层模块 不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。

依赖倒转原则要求正对接口编程,不要针对实现编程。依赖倒转原则要求在程序代码中传递参数是或在关联关系中尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回声明,以及数据类型的转换等,而不要用具体类来做这些事。为了确保该原则的应用,一个具体的类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。

在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样如果系统行为发生变化,只需要对抽象层进行扩展,并修改配置文件,而无需修改原有系统代码,在不修改的情况下来扩展系统的功能,满足开闭原则的要求。

在实现依赖倒转原则时需要针对抽象层编程,而将具体类的对象通过依赖注入的方式注入到其他对象中,常用注入方式:构造器注入,设值注入(setter注入)和接口注入(侵入性极强:被注入类依赖注入接口,违反 “依赖倒转原则”(高层类依赖了注入接口这个 “细节”),几乎淘汰)。

接口隔离原则

定义:客户端不应该依赖那些它不需要的接口。

在面向对象编程语言中,实现一个接口需要实现该接口中定义的所有方法,因此大的总接口使用起来不一定很方便,为了使接口的职责单一,需要将大接口中的方法根据其职责不同分别放在不同的小接口中,以确保每个接口使用起来都较为方便并都承担某一单一角色。该接口应该尽量细化,同时接口中的方法应该尽量少,每个接口中只包含一个客户端所需的方法即可,这种机制也被称为“定制服务”。

合成复用原则

合成复用原则又被称为组合/聚合复用原则。

定义:优先使用对象组合,而不是通过继承来达到复用的目的。
尽量使用「组合(Composition)」或「聚合(Aggregation)」的方式复用代码,而非「继承(Inheritance)」,通过「组合 / 聚合」实现代码复用,从而降低系统耦合度,提高灵活性和可维护性。

新对象应通过将已有对象纳入其中(组合 / 聚合),复用其行为和属性,而非通过继承已有对象;

继承仅适用于「is-a」(是一个)关系,组合 / 聚合适用于「has-a」(有一个)关系。

继承是 “白箱复用”(子类暴露父类细节),组合 / 聚合是 “黑箱复用”(复用对象的行为,隐藏内部细节)

迪米特法则

迪米特法则又称最少知识原则。

定义:每一个软件单位对其他单位都只有最少知识,而且局限于那些与本单位密切相关的软件单位。

迪米特法则要求一个软件实体应当尽可能少地与其他实体发生相互作用。如果一个系统符合迪米特法则,那么当其中的某一个模块发生修改时就会少量的影响其他模块,扩展会相对容易,这是对软件实体之间通信的限制,迪米特法则要求限制软件实体之间通信的深度和宽度。应用迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。

一个对象应该对其他对象 “知道得越少越好”,只与 “直接朋友” 交互,不与 “陌生人” 直接通信

朋友包括:

  1. 当前对象本身

  2. 以参数类型传入当前对象方法中的对象。

  3. 当前对象的成员对象。

  4. 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友。

  5. 当前对象所常见的对象。

迪米特法则要求在设计系统时应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生直接的相互作用,如果其中一个对象需要调用另一个对象的方法,可以通过第三者转发这个调用。就是通过引入一个合理的第三者来降低现有对象之间的耦合度。