面向对象六大设计原则

设计原则和设计模式的关系

面向对象的分析设计,需要遵循六大设计原则,这些设计原则大都会从思想上指导面向对象分析设计的正确方向,掌握这些原则能帮助我们更好的理解面向对象的概念,也能更好的理解设计模式。因为在实际开发中,也需要综合考虑业务需求、功能、实现难度、系统性能、时间与空间等很多方面的问题,所以很少做到完全遵守,总是在有意无意的违反一些或者是部分设计原则,这时便需要综合权衡其利弊。
设计模式是针对某个场景下某些问题的某个具体的解决方案。也就是说设计模式就是这些设计原则的一些具体的体现,因此设计模式也是应该遵守这些原则的。所以,学习设计模式,首先要学习的就是设计原则。

六大设计原则

  • 单一职责原则——SRP
  • 开闭原则——OCP
  • 里式替换原则——LSP
  • 依赖倒置原则——DIP
  • 接口隔离原则——ISP
  • 迪米特原则——LOD

六大设计原则关系图

面向对象六大设计原则1.

1.单一职责原则 (Single Responsibility Principle)

单一职责原则,简称SRP,定义是应该有且仅有一个类引起类的变更,即:一个类只负责一个职责。

优点:

  • 类的复杂性降低,实现什么职责都有明确的定义;
  • 逻辑变得简单,类的可读性提高了,而且,因为逻辑简单,代码的可维护性也提高了;
  • 变更的风险降低,因为只会在单一的类中的修改。

2.里氏替换原则 (Liskov Substitution Principle)

单一职责原则,简称LSP。定义如下:

复杂定义:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有对象o1都替换成o2的时候,程序P的行为都没有发生变化,那么类型T2是类型T1的子类型。

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

通俗地讲,就是:子类可以扩展父类的功能,但不能改变父类原有的功能。

面向对象的三大特征是封装、继承和多态。其中的继承,当子类继承父类时,虽然可以复用父类的代码,但是父类的属性和方法对子类都是透明的,子类可以随意修改父类的成员。若需求变更,子类对父类的方法进行了一些复写的时候,其他的子类可能就需要随之改变,这在一定程度上就违反了封装的原则,解决的方案就是引入里氏替换原则。

里氏替换原则为良好的继承定义了一个规范,它包含了4层含义:

  • 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
  • 子类可以有自己的个性,可以有自己的属性和方法。
  • 子类覆盖或重载父类的方法时输入参数可以被放大。
  • 子类覆盖或重载父类的方法时输出结果可以被缩小,也就是说返回值要小于或等于父类的方法返回值。

3.依赖倒置原则 (Dependence Inversion Principle)

依赖倒置原则,简称DIP,定义是:

高层模块不应该依赖底层模块,两者都应该依赖其抽象;

抽象不应该依赖细节;

细节应该依赖抽象。

不可分割的原子逻辑就是底层模块,原子逻辑的再组装就是高层模块。
在Java中,抽象是指接口或抽象类,两者都不能被实例化;而细节是实现接口或继承抽象类产生的类,也就是可以被实例化的实现类。依赖倒置原则是指模块间的依赖是通过抽象来发生的,实现类之间不发生直接的依赖关系,其依赖关系是通过接口是来实现的,这就是俗称的面向接口编程。所以说依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。

4.接口隔离原则 (Interface Segregation Principle)

接口隔离原则,简称ISP,定义是:

客户端不应该依赖它不需要的接口

也就是说客户端需要什么接口就提供什么接口,把不需要的接口剔除掉,这就需要对接口进行细化,保证接口的纯洁性。换成另一种说法就是,类间的依赖关系应该建立在最小的接口上,也就是建立单一的接口。

建立单一接口,这里需要和单一职责区分。单一职责原则要求的是类和接口职责单一,注重的是职责,一个职责的接口是可以有多个方法的,而接口隔离原则要求的是接口的方法尽量少,模块尽量单一,如果需要提供给客户端很多的模块,那么就要相应的定义多个接口,不要把所有的模块功能都定义在一个接口中,那样会显得很臃肿。

5.迪米特原则 (Law of Demeter)

迪米特原则,简称LoD,也被称为最少知识原则,它描述的规则是:

一个对象应该对其他对象有最少的了解

也就是说,一个类应该对自己需要耦合或调用的类知道的最少,类与类之间的关系越密切,耦合度越大,那么类的变化对其耦合的类的影响也会越大,这也是我们面向设计的核心原则:低耦合,高内聚。

迪米特法则还有一个解释:只与直接的朋友通信。

什么是直接的朋友呢?每个对象都必然与其他对象有耦合关系,两个对象的耦合就成为朋友关系,这种关系的类型很多,例如组合、聚合、依赖等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。

6.开闭原则  (Open Closed Principle)

开闭原则,简称OCP,是Java世界里最基础的设计原则。定义是:     

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。


简而言之,在编程过程中,需求会不断变化,我们的软件实体应该通过扩展来方式来实现变化,而不是通过修改已有的代码实现变化。所以,我们的程序需要有易于扩展、易于维护、易于升级等特性。
遵循开闭原则的最好手段是抽象,用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。但从开闭原则的角度说,更好的方式是面向接口编程,这样可以更好的扩展性,同时也可降低耦合,可提高系统的稳定性。