开放封闭原则 (OCP,Open For Extension, Closed For Modification Principle)
类的改动是通过增加代码进行的,而不是修改源代码。
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。
即:对扩展开放,对修改关闭,增加功能是通过增加代码实现的,而不是去修改原来的代码。
在开闭原则的定义中,软件实体可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类。
任何软件都需要面临一个很重要的问题,即它们的需求会随时间的推移而发生变化。当软件系统需要面对新的需求时,我们应该尽量保证系统的设计框架是稳定的。如果一个软件设计符合开闭原则,那么可以非常方便地对系统进行扩展,而且在扩展时无须修改现有代码,使得软件系统在拥有适应性和灵活性的同时具备较好的稳定性和延续性。随着软件规模越来越大,软件寿命越来越长,软件维护成本越来越高,设计满足开闭原则的软件系统也变得越来越重要。
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在Java、C#等编程语言中,可以为系统定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中完成。在很多面向对象编程语言中都提供了接口、抽象类等机制,可以通过它们定义系统的抽象层,再通过具体类来进行扩展。如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。
简单案例:
注:结合单一职责原则,能够很好的运用开闭原则
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
/*开闭原则 demo
*->对扩展开放、对修改关闭
* 计算器类
*
*抽象化是实现开闭原则的关键步骤
*/
class Caculator{
public:
virtual void setOperatorNum(int a, int b) = 0;
virtual int getResult() = 0;
};
//加法计算器
class PlusCacaulator: public Caculator{
public:
virtual void setOperatorNum(int a, int b){
m_a = a;
m_b = b;
}
virtual int getResult(){
return m_a + m_b;
}
private:
int m_a;
int m_b;
};
//减法计算器
class MinusCacaulator : public Caculator{
public:
virtual void setOperatorNum(int a, int b){
m_a = a;
m_b = b;
}
virtual int getResult(){
return m_a - m_b;
}
private:
int m_a;
int m_b;
};
//乘法计算器
class MutiplyCacaulator : public Caculator{
public:
virtual void setOperatorNum(int a, int b){
m_a = a;
m_b = b;
}
virtual int getResult(){
return m_a * m_b;
}
private:
int m_a;
int m_b;
};
void test01(){
Caculator* cal = new PlusCacaulator;
cal->setOperatorNum(10, 20);
cout << "ret :" << cal->getResult() << endl;
delete cal;
cal = new MinusCacaulator;
cal->setOperatorNum(30, 20);
cout << "ret :" << cal->getResult() << endl;
delete cal;
cal = NULL;
}
int main(void){
test01();
return 0;
}
此时,如果想要加入取模运算,只需要加一个取模运算类,虽然能加了代码量,但是使用起来、维护起来确实很方便。
/*增加取模运算*/
class ModulesCacaulator: public Caculator{
public:
virtual void setOperatorNum(int a, int b){
m_a = a;
m_b = b;
}
virtual int getResult(){
return m_a % m_b;
}
private:
int m_a;
int m_b;
};