核心思想
开放-封闭原则:是指软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。
对扩展开放,意味着有新的需求或变化时,可以对先有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
开放-封闭原则的意思是说,你设计的时候,时刻要考虑,尽量让这个类足够好,写好了就不要去修改了,如果新需求来,我们增加一个类就完事了,原来的代码能不动则不动。
但是,我们在做任何系统的时候,都不要指望系统一开始时需求确定,就再也不会变化,这是不显示也不科学的想法,而既然需求是一定会变化的,那么如何在面对需求的变化时,设计的软件可以相对容易修改,不至于说,新需求以来,就要把整个程序推倒重来。怎样的设计才能面对需求的改变却可以保持相对稳定,从而使得系统可以在第一个版本以后不断推出新的版本呢?开放-封闭给我们答案
例子:
下面的这个小程序为计算两个数的和,只有着一个功能(在windows窗体应用程序)
部分代码展示
private void button1_Click(object sender, EventArgs e)
{
string str1 = textBox1.Text;
string str2 = textBox2.Text;
int num1 = Convert.ToInt32(str1);
int num2 = Convert.ToInt32(str2);
int result = num1 + num2;
textBox3.Text = Convert.ToString(result);
}
如果现在我需要让这个程序能够实现加法、减法、乘法、除法运算,那对于这个程序来说再添加一种运算程序需要对整体的代码都要修动,所以最好的办法便是重构。
需求改变,改动后代码(在控制台)
客户端代码
Operation oper;
oper = OperationFactory.createOperate("-"); //运算符号
oper.NumberA = 8; //假设的NumberA为8
oper.NumberB = 2; //假设的NumberB为2
double result = oper.GetResult();
Console.WriteLine("结果是{0}",result );
Console.ReadKey();
运算类
public class Operation
{
private double _numberA = 0;
private double _numberB = 0;
public double NumberA
{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB
{
get { return _numberB; }
set { _numberB = value; }
}
public virtual double GetResult()
{
double result = 0;
return result ;
}
}
加、减、乘、除代码
class OperationAdd : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA + NumberB;
return result;
}
}//加法类,继承运算类
class OperationSub : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA - NumberB;
return result ;
}
}//减法类,继承运算类
class OperationMul : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA * NumberB;
return result;
}
}//乘法类,继承运算类
class OperationDiv : Operation
{
public override double GetResult()
{
double result = 0;
if (NumberB == 0)
throw new Exception("除数不能为0");
result = NumberA / NumberB;
return result;
}
}//除法类,继承运算类
简单工厂运算类
public class OperationFactory
{
public static Operation createOperate(string operate)
{
Operation oper = null;
switch (operate)
{
case "+":
oper = new OperationAdd();
break;
case"-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
这样如果需求再次改变,需要可以计算平方的算法,那么只需要在加上一个平方类便可。
图解
这样既能保证了开放-封闭原则,有能体现之前所说的简单工厂模式
开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所生成的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而,对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。