最近开始学习《大话设计模式》这本书,以每章一篇博客的形式把学习心得记录下来。代码部分使用的均为C#,开发工具是VS2013,我的代码可以在[我的GitHub](https://github.com/12301013-SunHaobo/DesignPatterns下载到
工厂是什么?就是批量生产东西的地方。
在工厂模式里,我们向工厂类传入不同的参数,他就会返回不同的具体实现。
以书中的计算器程序为例,最简单的写法当然是所有代码放一起,不使用任何设计模式,读两个数字和一个运算符,在switch语句里根据不同的运算符对两个数字进行不同的操作,最后输出结果。
作为一个小黑框程序这样写就够了,但如果考虑一下程序的可复用性呢?比如如果要写一个有界面的计算器呢?在读这本书以前,我的做法肯定是把控制台的代码粘过去,然后把获取数字和运算符的方法从控制台读取修改成从界面获取,最后的输出改成调用界面控件显示,这样就完成了。
但有一种明显更好的做法,就是把数据的获取和计算过程分离,把计算的过程封装成一个函数,接受两个数字和一个运算符作为参数并返回计算结果,然后对这个函数进行调用。那么这个函数就是可复用的。小黑框能用,界面程序也能用,甚至网页应用、手机应用也能直接拿去用。
现在我们的计算器完成了,但如果要增加计算器的功能呢?比如要增加一个开平方的运算,怎么办。其实很简单啊,只要在计算函数的switch里增加一个分支就行了。这样做的后果就是,要增加一个功能,就必须**修改原有的代码**,而最好的情况是我们希望在给程序增加功能的时候,只需要增加实现新功能的代码,而不需要修改原有的部分。
该怎么做呢?工厂模式闪亮登场。
先来一个抽象类,成员变量有两个,数字A和数字B
public class Operation
{
private double _numberB = 0;
private double _numberA = 0;
public double NumberA
{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB
{
get { return _numberB; }
set { _numberB = value; }
}
public virtual double GetResult()
{
return 0;
}
}
加法运算类的具体实现,继承了运算抽象类,重写GetResult方法:
class OperationAdd:Operation
{
public override double GetResult()
{
return NumberA + NumberB;
}
}
其他三种基本运算的实现类跟加法类似,不再赘述。
关键的工厂类:
public class OperationFactory
{
public static Operation createOperation(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;
default:
throw new Exception("不支持的运算");
}
return oper;
}
}
主函数的代码:
static void Main(string[] args)
{
Console.WriteLine("计算A+-*/B");
Console.Write("输入数字A:");
string strNumberA = Console.ReadLine();
Console.Write("输入运算符:");
string strOperate = Console.ReadLine();
Console.Write("输入数字B:");
string strNumberB = Console.ReadLine();
Operation oper = OperationFactory.createOperation(strOperate);
oper.NumberA = Convert.ToDouble(strNumberA);
oper.NumberB = Convert.ToDouble(strNumberB);
Console.WriteLine(oper.GetResult());
Console.ReadLine();
}
哈哈,工厂模式的计算器完成了。对这个计算器增加新运算时,就只要新增一个继承自抽象类的心运算类,并在其中重新GetResult方法就好了。
可是,还是要修改工厂类啊?
是这样的,但是不用修改已经实现好的其他运算类。
第1章——简单工程模式
工厂是什么?就是批量生产东西的地方。
在工厂模式里,我们向工厂类传入不同的参数,他就会返回不同的具体实现。
以书中的计算器程序为例,最简单的写法当然是所有代码放一起,不使用任何设计模式,读两个数字和一个运算符,在switch语句里根据不同的运算符对两个数字进行不同的操作,最后输出结果。
作为一个小黑框程序这样写就够了,但如果考虑一下程序的可复用性呢?比如如果要写一个有界面的计算器呢?在读这本书以前,我的做法肯定是把控制台的代码粘过去,然后把获取数字和运算符的方法从控制台读取修改成从界面获取,最后的输出改成调用界面控件显示,这样就完成了。
但有一种明显更好的做法,就是把数据的获取和计算过程分离,把计算的过程封装成一个函数,接受两个数字和一个运算符作为参数并返回计算结果,然后对这个函数进行调用。那么这个函数就是可复用的。小黑框能用,界面程序也能用,甚至网页应用、手机应用也能直接拿去用。
现在我们的计算器完成了,但如果要增加计算器的功能呢?比如要增加一个开平方的运算,怎么办。其实很简单啊,只要在计算函数的switch里增加一个分支就行了。这样做的后果就是,要增加一个功能,就必须**修改原有的代码**,而最好的情况是我们希望在给程序增加功能的时候,只需要增加实现新功能的代码,而不需要修改原有的部分。
该怎么做呢?工厂模式闪亮登场。
先来一个抽象类,成员变量有两个,数字A和数字B
public class Operation
{
private double _numberB = 0;
private double _numberA = 0;
public double NumberA
{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB
{
get { return _numberB; }
set { _numberB = value; }
}
public virtual double GetResult()
{
return 0;
}
}
加法运算类的具体实现,继承了运算抽象类,重写GetResult方法:
class OperationAdd:Operation
{
public override double GetResult()
{
return NumberA + NumberB;
}
}
其他三种基本运算的实现类跟加法类似,不再赘述。
关键的工厂类:
public class OperationFactory
{
public static Operation createOperation(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;
default:
throw new Exception("不支持的运算");
}
return oper;
}
}
主函数的代码:
static void Main(string[] args)
{
Console.WriteLine("计算A+-*/B");
Console.Write("输入数字A:");
string strNumberA = Console.ReadLine();
Console.Write("输入运算符:");
string strOperate = Console.ReadLine();
Console.Write("输入数字B:");
string strNumberB = Console.ReadLine();
Operation oper = OperationFactory.createOperation(strOperate);
oper.NumberA = Convert.ToDouble(strNumberA);
oper.NumberB = Convert.ToDouble(strNumberB);
Console.WriteLine(oper.GetResult());
Console.ReadLine();
}
哈哈,工厂模式的计算器完成了。对这个计算器增加新运算时,就只要新增一个继承自抽象类的心运算类,并在其中重新GetResult方法就好了。
可是,还是要修改工厂类啊?
是这样的,但是不用修改已经实现好的其他运算类。