問(wèn)題引入
實(shí)現(xiàn)一個(gè)簡(jiǎn)單的計(jì)算器:輸入數(shù)字和加減乘除操作符凝赛,輸出結(jié)果
按照單純的面向過(guò)程方法,可能有以下實(shí)現(xiàn):
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Num1: ");
double num1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Num2: ");
double num2 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Oper: ");
string strOper = Console.ReadLine();
double res = 0d;
switch(strOper)
{
///
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Press any key to quit...");
Console.ReadKey();
}
}
以上代碼暫時(shí)可以滿足需求琐脏,但是如果現(xiàn)在需要增加一個(gè)case: 求模運(yùn)算坚嗜,那此時(shí)便需要修改switch
中的代碼了,這不符合對(duì)修改封閉继蜡,對(duì)擴(kuò)展開(kāi)放的原則回俐。此時(shí)可以考慮簡(jiǎn)單工廠模式:
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Num1: ");
double num1 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Num2: ");
double num2 = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Oper: ");
string strOper = Console.ReadLine();
double res = 0d;
Operation oper = OperationFactory.createOperate(strOper);
oper.Num1 = num1;
oper.Num2 = num2;
Console.WriteLine(Convert.ToString(oper.GetResult()));
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Press any key to quit...");
Console.ReadKey();
}
}
abstract class Operation
{
private double _num1;
private double _num2;
public double Num1
{
get { return _num1; }
set { _num1 = value; }
}
public double Num2
{
get { return _num2; }
set { _num2 = value; }
}
public abstract double GetResult();
}
class OperationAdd : Operation
{
public override double GetResult()
{
return Num1 + Num2;
}
}
class OperationSub : Operation
{
public override double GetResult()
{
return Num1 - Num2;
}
}
class OperationMul : Operation
{
public override double GetResult()
{
return Num1 * Num2;
}
}
class OperationDiv : Operation
{
public override double GetResult()
{
if (Num2 == 0)
throw new Exception("Divisor can not be zero!!!");
return Num1 / Num2;
}
}
class OperationFactory
{
public static Operation createOperate(string type)
{
Operation oper = null;
switch (type)
{
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
在上述模式中,我們首先抽象出一個(gè)Operation
抽象類稀并,統(tǒng)一了GetResult
操作仅颇,然后不同的運(yùn)算操作都繼承自這個(gè)抽象類,并根據(jù)不同的運(yùn)算自己實(shí)現(xiàn)GetResult
碘举。接著使用一個(gè)OperationFactory
實(shí)現(xiàn)了switch
的功能忘瓦,這樣客戶端只需要把運(yùn)算的類型傳進(jìn)去即可。
當(dāng)我們需要增加一種運(yùn)算的時(shí)候引颈,需要做兩步:
- 定義一個(gè)新的類繼承自
Operation
耕皮,實(shí)現(xiàn)GetResult
接口 - 在
OperationFactory
的switch
語(yǔ)句中增加一個(gè)對(duì)應(yīng)的分支
顯然,使用了簡(jiǎn)單工廠模式线欲,我們還是避免不了修改switch
里面的代碼明场,不過(guò)相比之前代碼,有以下優(yōu)點(diǎn):
- 封裝了
switch
李丰,客戶端不需要自己判斷 - 將不同的算法分離苦锨,新增加一個(gè)算法只需要實(shí)現(xiàn)父類所要求的接口,原來(lái)的算法不會(huì)被暴露出來(lái)趴泌,減少被誤改的風(fēng)險(xiǎn)
缺點(diǎn)也是有的:
- 若是要頻繁增加算法舟舒,需要不斷修改簡(jiǎn)單工廠里的判斷分支
- 客戶端使用時(shí)需要知道兩個(gè)類:
Operation
和OperationFactory