面向对象的设计原则
1.单一职责原则(SRP)
定义:对于一个类,有且仅有一个引起它变化的原因。
单一职责的英文全称是Single Responsibility Principle, 简称SRP。
通俗讲就是我们不要让一个类承担过多的职责。如果一个类承担的职责过多,如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会导致类的行为功能发生变化。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到破坏。我们要做的就是要分离这种多职责的变化,从而降低耦合度。
SRP遵循的OO设计原则就是:封装变化的部分。找出应用中那些会变化的地方,把他们独立出来并封装,将其和不变的代码隔离。(将相同的变化封装到一个接口或者抽象类中,将不同的变化封装到不同的接口和抽象类中)
单一职责适用于类、接口,以及方法,即不管是类、接口还是方法都要做到只干一件事。
2.开放封闭原则(OCP)
定义:一个软件实体应该对扩展开放,对修改关闭。
开闭原则的英文全称是Open-Close Principle, 简称OCP。
这里所说的软件实体包括:项目中按照一定逻辑规则划分的模块、类、抽象类以及方法。
开放封闭有两个含义,一个是对于拓展是开放的,另一个是对于修改是封闭的。一个软件在生命周期内总要面对需求的变化,那么对于开发者来说怎么处理变化的需求,在实际当中往往是新需求一来,我们就要把类重新改一遍, 这显然是令人头疼的。开闭原则告诉我们的是,尽量通过扩展软件的实体来实现变化,而不是通过修改已有的代码来完成变化。 可以说开闭原则是对软件实体的未来变化的一种约束性的原则。
3.里氏替换原则(LSP)
定义:所有引用基类(父类)的地方必须能透明地使用其子类的对象。
里氏替换原则英文全称是Liskov Substitution Principle,简称LSP。
对定义简单的理解:凡是父类出现的地方子类就可以出现,而且替换为子类也不会产生任何错误和异常。使用者可能根本不需要关心使用的是父类还是子类,但是,反过来就不行,有子类出现的地方,父类不一定能适应。
4.依赖倒置原则(DIP)
定义:高层模块不应该依赖低层模块,两个都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
依赖倒置原则英文全称是Dependence Inversion Principle, 简称DIP。
高层模块和低层模块的理解: 每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是低层模块,原子逻辑的再组装就是高层模块。
在Java中,抽象就是指接口或者抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或者继承抽象类而产生的就是细节,也就是可以通过new产生的对象。高层模块就是调用端,低层模块就是具体实现类。
依赖倒置原则在Java中的体现就是:
模块间通过抽象发生,实现类之间不发生直接依赖关系,其依赖关系是通过接口或者抽象类产生的。
接口或抽象类不依赖于实现类。
实现类依赖接口或抽象类。
一句话总结依赖倒置原则就是:面向接口编程,而不是面向实现编程。
如何使用依赖倒置原则,遵循以下几个原则:
-
每个类尽量有接口或者抽象类,接口和抽象类都属于抽象,有了抽象才能依赖倒置
-
变量的表面类型尽量是接口或者抽象类
-
尽量不要覆写基类的方法, 子类尽量不要覆写抽象类已经实现的方法。
-
开发阶段尽量不要从具体类派生新类,只是在开发阶段,因为在维护阶段是要不断扩展修改的。
5.接口隔离原则(ISP)
定义:一个类对另一个类的依赖应该建立在最小的接口上,客户端不应该依赖它不需要的接口。
接口隔离原则英文全称Interface Segregation Principle,简称ISP。
这里接口的含义有两种:
实例接口, 可以用new的实现类都属于实例接口。
类接口,在java中就是interface声明的接口或者是抽象类。
对定义的理解:接口要做到细化单一,不用建立庞大臃肿的接口。接口中的方法尽量少。为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。如果有一个接口里面包含了各种模块的方法,那么就需要进行细化拆分,但细化拆分并不是无限制的细化每一个方法就对应写一个接口,细化拆分的下限和底线是做到满足单一职责,如果都不满足单一职责了那么接口的细化就没有意义了。在为一个类提供定制服务的时候,只暴露那些客户需要的方法,隐藏那些客户不需要的方法,做到以最少的方法完成最多的事,提高内聚。
6.迪米特法则(LOD)
定义:一个软件实体应当尽可能少地与其他实体发生相互作用。
迪米特法则(Law of Demeter,LoD)又叫作最少知识原则(Least Knowledge Principle 简写LKP)。
迪米特法则要求我们尽量或者减少类之间的直接交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果一个对象的某一个方法需要调用另一个对象的诸多方法,可以通过第三者转发这个调用,调用者对被调用者内部的情况知道的越少越好。