一、简介
在程序设计领域,SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)是由罗伯特·C·马丁在21世纪早期引入的记忆术首字母缩略字,指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,它们使得一个程序员开发一个容易进行软件维护和扩展的系统变得更加可能。
SOLID所包含的原则是通过引发编程者进行软件源代码的代码重构进行软件的代码异味清扫,从而使得软件清晰可读以及可扩展时可以应用的指南。SOLID被典型的应用在测试驱动开发上,并且是敏捷开发以及自适应软件开发的基本原则的重要组成部分。
二、六大原则
1、单一原则(Single Responsibility Principle):一个类或者一个方法只负责一项职责,尽量做到类的只有一个行为原因引起变化;
单一职责原则(Single Responsibility Principle,SRP)规定,每个软件单元,包括组件、类和函数,应该只有一个单一且明确定义的职责(改变的原因),即每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有这个类的服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。
class Rectangle{
public:
int Height { get; set; }
int Width { get; set; }
double Area() {
return Width * Height;
}
void Draw(Form form) {
...
}
}
Rectangle类的设计就违反了单一职责原则,该类包含了矩形数据结构,也包含了矩阵的绘制方法,两种概念的耦合会产生不少负面影响,比如使用计算面积时不得不包含GUI库的引用,增加了编译链接时间。
按照SRP的指导思想,应该将Rectangle类分拆为两个行为单一且明确定义的类。
class GeometricRectangle {
public:
int Height { get; set; }
int Width { get; set; }
double Area() {
return Width * Height;
}
}
class Rectangle {
public:
void Draw(Form form, GeometricRectangle geometric) {
...
}
}
2、里氏替换原则(LSP liskov substitution principle):子类可以扩展父类的功能,但不能改变原有父类的功能;(本质其实就是c++的多态)
(目的:增强程序的健壮性)实际项目中,每个子类对应不同的业务含义,使父类作为参数,传递不同的子类完成不同的业务逻辑。
1.子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
2.子类中可以增加自己特有的方法。
3.当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
4.当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
3、依赖倒置原则(dependence inversion principle):面向接口编程;(通过接口作为参数实现应用场景)
抽象就是接口或者抽象类,细节就是实现类
含义:
上层模块不应该依赖下层模块,两者应依赖其抽象;
抽象不应该依赖细节,细节应该依赖抽象;
通俗点就是说变量或者传参数,尽量使用抽象类,或者接口;
【接口负责定义public属性和方法,并且申明与其他对象依赖关系,抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑】
4、接口隔离(interface segregation principle):建立单一接口;(扩展为类也是一种接口,一切皆接口)
定义:
a.客户端不应该依赖它不需要的接口;
b.类之间依赖关系应该建立在最小的接口上;
简单理解:复杂的接口,根据业务拆分成多个简单接口;(对于有些业务的拆分多看看适配器的应用)
【接口的设计粒度越小,系统越灵活,但是灵活的同时结构复杂性提高,开发难度也会变大,维护性降低】
5、迪米特原则(law of demeter LOD):最少知道原则,尽量降低类与类之间的耦合;
一个对象应该对其他对象有最少的了解
为了解释迪米特法则,我们通过代码进行解释。根据本单一职责原则,我们将汽车分为了许多功能明确的类别,Driver对象的drive函数实现如下,并给出了依赖关系图。
class Driver {
public:
// ...
void drive(Car& car) const {
Engine& engine = car.getEngine();
FuelPump& fuelPump = engine.getFuelPump();
fuelPump.pump();
Ignition& ignition = engine.getIgnition();
ignition.powerUp();
Starter& starter = engine.getStarter();
starter.revolve();
}
// ...
};
6、开闭原则(open closed principle):用抽象构建架构,用实现扩展原则
开闭原则(Open Closed Principle, OCP)指出软件实体(模块、类、函数等)对扩展应该是开放的,对修改应该是封闭的。OCP是构建可维护性和可重用性代码的基础。它强调设计良好的代码可以不通过修改而扩展,新的功能通过添加新的代码来实现,而不需要更改已有的可工作的代码。抽象(Abstraction)和多态(Polymorphism)是实现这一原则的主要机制,而继承(Inheritance)则是实现抽象和多态的主要方法。
部分内容来自:https://zhuanlan.zhihu.com/p/114374066