面向对象的SOLID五大原则

前序做C语言开发的应该都知道,C是面向过程开发的,而c++是面向对象开发的 。而封装、继承与多态是面向对象开发的三大特征 。
但你可能不知道OOD(Object-Oriented Design)还有五大基本原则,被Bob大叔称为SOLID原则,字母为每个原则的首字母,遵循这些原则能够让你的代码在扩展性、维护性以及重用性提高 。而这些不正是我们所追求的吗?
接下来我们就一块学习学习这些原则,内容较多,建议先收藏后反复观看,文章末尾有很多参考链接 。
五大基本原则-SOLID1. SRPSRP(The Single Responsibility Principle)单一职责原则 。
SRP是SOLID五大设计原则中最容易被误解的一个,SRP不就是每个模块都应该只做一件事吗?非也非也,这只是在实现底层细节的实际原则,并非是SRP的全部 。
SRP最初是这样描述的:

任何一个模块都应该有且只有一个被修改的原因(There should never be more than one reason for a class to change)
SRP的定义几经迭代,最终被Robert C.Martin在《Clean Architecture》中定义为:
任何一个软件模块都应该只对某一类行为者负责
那么上文中提到的软件模块究竟是指什么呢?大部分情况下,其最简单的定义就是指一个源代码文件 。然而有些编程语言和编程环境并不是用源代码文件来存储程序的 。在这些情况下,软件模块指的就是一组紧密相关的函数和数据结构 。
来看一个正面例子,C标准库中的<math.h>模块就是用来处理数学相关的,<string.h>模块就是用来处理字符串相关的的,等等...,每个模块职责都比较明确 。
再来看一个反面例子,还记得刚开始学习单片机编程的时候,项目工程中从始至终就一个main源文件,真的是连头文件都不写的,一个main里面包含了LED、按键等相关全部代码,这明显是不符合SRP这一原则的 。就像下图一样 。
面向对象的SOLID五大原则

文章插图
 
2. OCPOCP(The Open-Closed Principle)开放封闭原则 。
OCP的定义如下:
软件实体应当对扩展开放,对修改关闭(Software entities should be open for extension,but closed for modification)
设计良好的计算机软件应该易于扩展,同时抗拒修改 。换句话说,一个良好的计算机系统应该在不需要修改的前提下就可以轻易被扩展 。
OCP是系统框架设计的主导原则,其主要目的是让系统易于扩展,同时限制其每次被修改所影响的范围 。实现的方式是通过将系统划分为一系列的组件,并且将这些组件的依赖关系按层次结构进行组织,使得高阶的组件不会因低阶组件被修改而受到影响 。
我们来看一个网络中协议的例子,如下图:
面向对象的SOLID五大原则

文章插图
 
图中分为三个层级,最上方层级最高,每个层级有若干组件,高层级的组件依赖低层级的组件 。
3. LSPLSP(LSP-Liskov Substitution Principle)里氏替换原则 。
LSP定义:
使用基类对象指针或引用的函数必须能够在不了解衍生类的条件下使用衍生类的对象(Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it)
里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现 。只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为 。
我们来看一个经典的反面案例,正方形(Square)与长方形(Rectangle) 。
那这里提出疑问了,正方形和长方形之间的继承关系是如何呢?
如果A is-a B,则认为B是基类,A为子类,A应该继承B 。那这个简单了,众所周知正方形是长方形,立即推,长方形是基类,正方形是子类,正方形应该继承长方形 。
面向对象的SOLID五大原则

文章插图
 
基类长方形中有SetHeight()和SetWidth()方法,但是子类正方形有一个特点,长和宽是相等的,所以在实现SetHeight()和SetWidth()都必须同时设置宽和高,我们来看代码 。


推荐阅读