开闭原则
959字约3分钟
2022-07-11
定义
开闭原则(The Open-Closed Principle ,OCP).
Software entities (classes, modules, functions) should be open for extension but closed for modification.
- 对扩展开放, 意味着有新的需求或变化时, 可以对现有代码进行扩展, 以适应新的情况.
- 对修改封闭, 意味着类一旦设计完成, 就可以独立完成其工作, 而不要对已有代码进行任何修改.
开闭原则是判断面向对象是否正确的最基本的原理.
作用
开闭原则是面向对象程序设计的终极目标, 它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性. 具体来说, 其作用如下:
- 对软件测试的影响: 软件遵守开闭原则的话, 软件测试时只需要对扩展的代码进行测试就可以了, 因为原有的测试代码仍然能够正常运行.
- 可以提高代码的可复用性: 粒度越小, 被复用的可能性就越大. 在面向对象的程序设计中, 根据原子和抽象编程可以提高代码的可复用性.
- 可以提高软件的可维护性: 遵守开闭原则的软件, 其稳定性高和延续性强, 从而易于扩展和维护.
实现方法
可以通过 "抽象约束, 封装变化" 来实现开闭原则, 即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层, 而将相同的可变因素封装在相同的具体实现类中.
- 将不变的部分抽象成接口.
- 接口最小功能原则. 接口越小, 可复用性越强. 不足的部分可以通过新的接口来实现.
- 模块之间通过抽象接口进行调用. 即使实现发生变化, 也无需修改调用方的代码.
示例
现在考虑实现一个功能: 创建一个画板, 可以绘制各种多边形.
反例
Shape.h
enumShapeType{isCircle, isSquare};
typedef struct Shape {
enumShapeType type
} shape;
Circle.h
typedef struct Circle {
enumShapeType type;
double radius;
Point center;
} circle;
void drawCircle( circle* );
Square.h
typedef struct Square {
enumShapeType type;
double side;
Point topleft;
} square;
void drawSquare( square* );
drawShapes.cpp
#include "Shape.h"
#include "Circle.h"
#include "Square.h"
void drawShapes( shape* list[], int n ) {
for( int i=0; i<n; i++ ) {
shape* s= list[i];
switch( s->type ) {
case isSquare:
drawSquare( (square*)s );
break;
case isCircle:
drawCircle( (circle*)s );
break;
}
}
}
我们可以看到, 在上面的例子中如果我们需要增加一种多边形时:
Shape
类不是扩展的, 需要增加enumShapeType
的枚举类型.drawShapes
不是封闭的, 需要修改代码新增一个case
.
正例
Shape.h
#ifndef SHAPE_H
#define SHAPE_H
class Shape {
public:
virtual void draw() = 0; // 纯虚函数
virtual ~Shape() {} // 虚析构函数
};
#endif
Circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
#include "Shape.h"
#include "Point.h" // 假设你有一个 Point 类型
class Circle : public Shape {
private:
double radius;
Point center;
public:
Circle(double r, Point c) : radius(r), center(c) {}
void draw() override {
// 绘制圆形的代码
}
};
#endif
Square.h
#ifndef SQUARE_H
#define SQUARE_H
#include "Shape.h"
#include "Point.h" // 假设你有一个 Point 类型
class Square : public Shape {
private:
double side;
Point topleft;
public:
Square(double s, Point tl) : side(s), topleft(tl) {}
void draw() override {
// 绘制正方形的代码
}
};
#endif
drawShapes.cpp
#include "Shape.h"
void drawShapes( shape* list[], int n ) {
for( int i=0; i<n; i++ ) {
list[i] -> draw();
}
}
上述代码中我们引入了一个抽象类, 使用了多态来绘制图形. 这样子如果未来需要新增绘制三角形的功能, 只需要添加如下代码并实现 draw()
方法即可.
Triangle.h
class Triangle : public Shape {
private:
Point p1, p2, p3;
public:
Triangle(Point a, Point b, Point c) : p1(a), p2(b), p3(c) {}
void draw() override {
// 绘制三角形的代码
}
};