最近阿猩的公司為解決一些問題,在新專案導入了Mediator模式,阿猩從一開始學.NET就有試著閱讀Design Pattern。剛好有這個契機Push自己,日後會花時間,嘗試理解不同Design Pattern,盡量不死記,試著內化成自己可以活用的知識,今天要練習的設計模式為工廠模式。
情境說明
假設目前要開發一套傳統計算機的程式,由客戶端輸入2個數字,並選擇計算方式,如加、減、乘、除。
釐清業務需求
回傳計算結果的程式,例如1+1 = 2,會需要完成一些工作,阿猩試著先將工作職責釐清,後續才能分別完成每個職責的程式碼。
例如
- 使用者傳入數字及計算方法
- 依使用者輸入條件,選擇計算方法。
- 各種使用方法的運算過程、或特別判定
- 取得計算結果
- 顯示計算結果
依職責建立物件
使用者傳入數字及計算方法
因阿猩使用.NET Framework主控台應用程式,一開始需要宣告共用變數,儲存使用者輸入的值,包含2個數字、計算方法符號及最後運算結果。
// 1. 宣告變數
decimal num1 = 0;
decimal num2 = 0;
string oper = string.Empty;
decimal result = 0;
// 2. 使用者輸入
console.WriteLine("請輸入第1個數字:");
decimal.TryParse(Console.ReadLine(), out num1);
Console.WriteLine("請輸入計算機操作 (Ex: +,-,*,/):");
oper = Console.ReadLine();
Console.WriteLine("請輸入第2個數字:");
decimal.TryParse(Console.ReadLine(), out num2);
依使用者輸入條件,選擇計算方法。
為了達到職責分離,將判斷計算方式,與取得結果的程式分離,使用者輸入加減乘除時,演算法工廠只需要判斷,接下來要用哪種算法,並產生對應的物件。但因為return類別只能有1個,故需回傳一個業務邏輯的父類別或抽象,可以使用Abstract、Interface、自定義類別,此處阿猩是使用Interface。
/// <summary>
/// 演算法工廠
/// </summary>
public class AlgorithmFactory
{
public static IAlgorithm CreateAlgorithm(string type)
{
switch (type)
{
case "+":
return new AddAlgorithm();
case "-":
return new SubAlgorithm();
case "*":
return new MulAlgorithm();
case "/":
return new DivAlgorithm();
default:
throw new ApplicationException(string.Format("Algorithm'{0}' cannot be created", type));
}
}
}
計算的運算過程、或特別判定
產生業務邏輯的物件,如AddAlgorithm、SubAlgorithm等,分別繼承IAlgorithm並實作。
/// <summary>
/// 加法演算法
/// </summary>
class AddAlgorithm : IAlgorithm
{
public decimal GetResult(decimal num1, decimal num2)
{
return num1 + num2;
}
}
}
/// <summary>
/// 減法演算法
/// </summary>
class SubAlgorithm : IAlgorithm
{
public decimal GetResult(decimal num1, decimal num2)
{
return num1 - num2;
}
}
取得計算結果
.NET Framework主控台應用程式的Program,阿猩將其視為WebAPI的Controller,只用於流程控制。呼叫AlgorithmFactory.CreateAlgorithm(oper),根據使用者輸入值,建立計算方法後,帶入2個數字,要用哪種方法計算,及如何算,都與Program無關。
// 3. 工廠模式
IAlgorithm Algorithm = AlgorithmFactory.CreateAlgorithm(oper);
result = Algorithm.GetResult(num1, num2);
輸出結果至螢幕
Console.WriteLine(string.Format("{0} {1} {2} = {3}", num1, oper, num2, result));
Console.ReadLine();
工廠模式思考重點
- 不同業務邏輯寫在各自的Object。
- 工廠模式可以解決的問題,是把判斷與實際業務分離。工廠只需要判斷生成哪個Object。
- 工廠新增時,Object類型為多到一,為return不同Object,應依賴於抽象或業務的共用父類別。如果畫成UML圖,會像是圖1
- New物件時,可定義為父層型別,例如 IAlgorithm iAlgorithm = new AddAlgorithm()