【設計模式】簡單工廠模式——以一個簡單的計算器為例
阿新 • • 發佈:2019-01-11
本文內容參考自《大話設計模式》(程傑 著)
注:以下程式碼為C#實現
1.拙劣的程式碼
class Program
{
static void Main(string[] args)
{
Console.Write("請輸入數字A:");
string A = Console.ReadLine();
Console.Write("請選擇運算子號(+、-、*、/):");
string B = Console.ReadLine();
Console.Write("請輸入數字B:" );
string C = Console.ReadLine();
string D = "";
if (B == "+")
D = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(C));
if (B == "-")
D = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(C));
if (B == "*")
D = Convert.ToString (Convert.ToDouble(A) * Convert.ToDouble(C));
if (O == "/")
D = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(C));
Console.WriteLine("結果是:" + D);
}
}
毛病:命名不規範,判斷分支做多次無用功,除數為0時出錯,輸入不是數字……
2.規範化
class Program
{
static void Main(string[] args)
{
try
{
Console.Write ("請輸入數字A:");
string strNumberA = Console.ReadLine();
Console.Write("請選擇運算子號(+、-、*、/):");
string strOperate = Console.ReadLine();
Console.Write("請輸入數字B:");
string strNumberB = Console.ReadLine();
string strResult = "";
switch (strOperate)
{
case "+":
strResult = Convert.ToString(Convert.ToDouble(strNumberA)
+ Convert.ToDouble(strNumberB));
break;
case "-":
strResult = Convert.ToString(Convert.ToDouble(strNumberA)
- Convert.ToDouble(strNumberB));
break;
case "*":
strResult = Convert.ToString(Convert.ToDouble(strNumberA)
* Convert.ToDouble(strNumberB));
break;
case "/":
if (strNumberB != "0")
strResult = Convert.ToString(Convert.ToDouble(strNumberA)
/ Convert.ToDouble(strNumberB));
else
strResult = "除數不能為0";
break;
}
Console.WriteLine("結果是:" + strResult);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("您的輸入有錯:" + ex.Message);
}
}
}
以上程式碼規範了,但是可重用性差!
3.業務的封裝
Operation運算類
public class Operation
{
public static double GetResult(double numberA, double numberB, string operate)
{
double result = 0d;
switch (operate)
{
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
result = numberA / numberB;
break;
}
return result;
}
}
客戶端程式碼
static void Main(string[] args)
{
try
{
Console.Write("請輸入數字A:");
string strNumberA = Console.ReadLine();
Console.Write("請選擇運算子號(+、-、*、/):");
string strOperate = Console.ReadLine();
Console.Write("請輸入數字B:");
string strNumberB = Console.ReadLine();
string strResult = "";
strResult = Convert.ToString(Operation.GetResult(Convert.ToDouble(strNumberA),
Convert.ToDouble(strNumberB), strOperate));
Console.WriteLine("結果是:" + strResult);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("您的輸入有錯:" + ex.Message);
}
}
問題:如果我要增加其他運算,或者是想要修改運算的法則,那麼其他程式碼都會受到影響,比如要重新編譯,除錯等等。
4.鬆耦合
Operation運算類
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;
}
}
在這裡,我們定義了一個虛擬函式,然後其他運算繼承操作類並實現該函式,這樣子,如果要增加其他運算,只需要增加一個類來繼承操作類就可以了,而且單個操作的修改完全不影響其他的運算!
5.簡單工廠模式
使用上面程式碼之後,我們在客戶端需要例項化相應的類,比如‘+’操作需要例項化OperationAdd,減操作需要例項化OperationSub,這樣子暴露給客戶的資訊太多了,客戶必須知道每個操作它對應的類!
使用簡單的工廠模式可以避免這個問題:
簡單運算工廠類
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;
}
}
客戶端程式碼
Operation oper;
oper = OperationFactory.createOperate(“+”);
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
如果一來,客戶端就簡化了很多,它只需要知道 OperationFactory,並通過createOperate傳入相應的操作就可以了!
當我們需要修改加法運算時,只需要修改OperationAdd,當我們需要增加其他運算時,只需要增加相應的運運算元類,並在運算類工廠中增加分支即可。
同時,介面顯示和我們的業務邏輯也是分離的~
UML圖: