描述
- 对于程序的扩展是开放的
- 对于程序牵一发而动全身的更改是封闭的
实现
模块可以操作一个抽象体。由于一个模块依赖一个固定的抽象体,所以抽象体对于更改是关闭的。但是他可以通过派生来达到扩展其行为的目的。
简单的说 符合 OCP 原则的设计 是对一个模块的改动是动过新增加代码实现的,而不是修改原先的代码,不会引起连锁反应。
示例
假如现在需要绘制图形界面,有圆形,矩形,三角形 等等 。需要创建一个列表,让后按一定的顺序绘制他们 。
- 遵循OCP 的设计
class Shape
{
public:
virtual void Draw() const = 0;
};
class Circle
:public Shape
{
public:
// 通过 Shape 继承
virtual void Draw() const override
{
std::cout << "circle" << std::endl;
}
};
class Square
:public Shape
{
public:
// 通过 Shape 继承
virtual void Draw() const override
{
std::cout << "Square" << std::endl;
}
};
- 使用“数据驱动”的方法实现封闭性
#include<iostream>
#include<typeinfo>
#include<vector>
#include<cstring>
#include<list>
class Shape
{
public:
virtual void Draw() const = 0;
//实现排序策略的封闭
bool Precedes(const Shape & s) const
{
auto this_name = typeid(*this).name();
auto s_name = typeid(s).name();
int this_ord = -1;
int s_ord = -1;
for (size_t i = 0; i < typeOrderTable.size(); i++)
{
if (strcmp(this_name,typeOrderTable.at(i))==0)
{
this_ord = i;
}
if (strcmp(s_name,typeOrderTable.at(i))==0)
{
s_ord = i;
}
if (this_ord!=-1 && s_ord!=-1)
{
break;
}
}
return this_ord < s_ord;
}
bool operator< (const Shape & s) const { return Precedes(s); }
private:
static std::vector<const char *> typeOrderTable;
};
class Circle
:public Shape
{
public:
// 通过 Shape 继承
virtual void Draw() const override
{
std::cout << "circle" << std::endl;
}
};
class Square
:public Shape
{
public:
// 通过 Shape 继承
virtual void Draw() const override
{
std::cout << "Square" << std::endl;
}
};
//图形绘制的先后顺序实际上是有这个数据表来驱动
//新派生的图形只需要修改一个表即可 不需要修改已有的代码实现
std::vector<const char *> Shape::typeOrderTable
{
typeid(Square).name(),
typeid(Circle).name()
};
//按序绘制所有图形方法的封闭
void DrawAllShape(std::list<Shape * > & shape_list)
{
//排序
shape_list.sort([](const Shape * a, const Shape* b) {return *a < *b; });
//渲染
for (const auto & v:shape_list)
{
v->Draw();
}
}
int main()
{
Circle *c1 = new Circle;
Circle * c2 = new Circle;
Square * s1 = new Square;
Square * s2 = new Square;
std::list<Shape *> list;
list.push_back(c1);
list.push_back(s1);
list.push_back(s2);
list.push_back(c2);
DrawAllShape(list);
system("pause");
return 0;
}