天天看点

面向对象程序6大设计原则一、单一职责原则二、里氏替换原则三、依赖倒置原则四、接口隔离原则五、迪米特原则六、开闭原则

一、单一职责原则

内容介绍

SRP,Single Responsibility Principle,中文翻译为“单一职责原则。
一个类应该有且仅有一个职责。一个类变化的原因应该不多于一个。

我的理解

要实现单一职责原则:
首先要了解“职责”。所谓职责,面向对象大师Robert. C. Martin有一个著名的定义:所谓一个类的职责就是引起该类变化的原因。如果一个类有多个职责,那么就会有多个不同的原因引起该类的变化,而变化就将带来维护等方面的困难。
其次,要对了解 “单一”。对“一”的理解将直接反映在对类的设计上。一件事情可能需要多个不同对象共同协作才能完成,每个对象自然有着不同的职责,那么这件事是不是“单一”的呢?从结果上看,该类对外提供了“单一”的功能,但是从实现过程上来看,却涉及到“多”个对象。所以,对于“一”的把握,就由经验和水平共同决定了。单一职责原则提醒我们在类的设计上应该足够专注

二、里氏替换原则

内容介绍

LSP, Liskov Substitution Principle, 中文翻译为“里氏替换原则”。

子类对象提供了父类对象所有的行为并且还添加了一些东西;如果针对每一个S类型的对象OS,这里都有一个T类型的对象OT,使得所有针对OT对象的程序可以在不改变程序行为的前提下用OS替换OT,那么我们就说类S是类T的子类。也就是说:

1. 子类必须实现或者继承父类所有的公有方法;

2. 子类的每个方法的输入参数必须和父类一样;

3. 子类方法的输出必须不比父类少。

我的理解

里氏替换原则实际上是对如何设计类间关系——继承关系的一种指导原则,它提示我们应该建立怎样的继承关系才便于“拥抱变化”、降低维护成本。如果子类无法提供父类的所有的公有方法,那么所有使用了父类对象的程序都必须进行修改以适应子类对象,但是如果满足里氏替换原则,那么对父类对象进行 “升级”就会变得简单而又安全,从而实现“拥抱变化”和降低维护成本的目的。

三、依赖倒置原则

内容介绍

DIP, DependencyInversion Principle, 中文翻译为“依赖倒置原则”。
高层模块不应该直接依赖底层模块,两者都应该依赖抽象;
抽象不应该依赖细节;
细节应该依赖抽象。

我的理解

高层模块定义了系统的功能架构,全面的描述系统的功能和组成结构。依赖倒置原则提示我们在对系统进行模块分层设计时高层模块不应该依赖底层具体模块,应该通过抽象完成高层模块的建筑,而底层模块也应该通过抽象实现。
依赖抽象的好处就在于灵活多变——只要一个类实现了抽象类所定义的方法,那么这个类就可以无缝地成为高层模块的底层实现,从而在保持系统高层模块稳定的同时又使系统的功能具有可扩展性。

四、接口隔离原则

内容介绍

ISP, Interface Segregation Principle,中文翻译为“接口隔离原则”。
客户端不应该被强迫去依赖它们不需要的接口;
类间依赖关系应该建立在最小接口之上。

我的理解

接口隔离原则提示我们在构筑类间依赖关系时所应遵守的原则——通过最小和最简接口建立依赖关系。

这一原则体现了基于接口编程的思想——类间的依赖关系通过接口实现而不是具体的实现类。基于接口编程同里氏替换原则有相似的好处——便于以最小的代价实现系统功能的扩展。

同时接口应该是简单的,过于庞大的接口意味着接口的设计可能不符合“单一职责原则”,从而使系统面临关系复杂、难以维护和扩展的困境。

简单、明确的类间依赖关系无疑有助于“拥抱变化”和降低维护成本。

五、迪米特原则

内容介绍

Law of Demeter, 也称为知识最少原则:一个对象应该对其他对象有最少的了解。

我的理解

使用者如果需要使用某一对象的某一功能,那么按照迪米特原则,使用者应当直接调用该对象提供的公有方法即可,使用者不应该了解功能的具体实现过程——这一过程应该被封装在功能提供者的内部。

使用者不应该了解提供者的细节知识,因为了解的细节越多,使用者本身的“专注度”就越有可能下降从而造成类间的依赖关系过于沉重,形成高耦合:一旦提供者的细节有所改变,使用者在此时也将被迫作出修改,这明显增加了维护成本。

六、开闭原则

内容介绍

OCP,Open-Closed Principle,中文翻译为“开闭原则”。
“Software entities(class,modules, functions,etc.) should be open for extension, but close for modification.”
即:软件实体(类、模块、函数等)应该对扩展开放,但是对修改关闭。

我的理解

在《设计模式之禅》中作者的观点是:Open for provider extension,closed for consumer modification. 即对提供者的扩展开放,对使用者的修改关闭。

也就是说,系统的设计应该便于扩展,而尽量避免修改。同时对于向系统添加新的功能也应该通过扩展已有系统进行,而不是直接修改原有系统。

七、一个中心,两个基本点

从上述分析过程中可以看出,六大设计原则都针对如何使系统有效地适应变化、降低系统维护成本这两个核心问题在不同层面给出了有效的解决方案:

  1. 单一职责原则在类的设计层面给出的解决方案是:一个类应该有且只有一个职责,该职责也是类将“变化”的原因;
  2. 里氏替换原则在类的继承关系层面给出的解决方案是:子类可以出现在任何父类出现的地方,而且子类应该有新增功能;
  3. 依赖倒置原则在系统模块设计层面给出的解决方案是:系统模块应该建立在抽象之上,而不是实现之上;同时抽象不应该依赖细节;
  4. 接口隔离原则和迪米特原则在类的依赖关系层面给出的解决方案是:类间的依赖关系应该通过最简接口实现;
  5. 开闭原则在系统(类、接口、模块、函数)整体设计层面给出了核心的解决方案:支持扩展,反对修改。
面向对象程序6大设计原则一、单一职责原则二、里氏替换原则三、依赖倒置原则四、接口隔离原则五、迪米特原则六、开闭原则

以“找到变化,封装变化”为中心的设计模式之道和以“基于接口编程,而不是基于实现编程”、“优先使用对象组合而不是类继承”为基本点的设计原则共同组成了面向对象程序设计的一系列规范基础,当然这也设计模式的基础。

最后,欢迎大家批评指正~

参考书籍:

《面向对象葵花宝典 : 思想、技巧与实践》李运华编著

《设计模式之禅(第二版)》秦小波著

继续阅读