1. 簡介
簡單工廠模式(Simple Factory Pattern):定義一個工廠類,根據不同的參數,創建並返回不同的類。其中這些類具有一個公共的父類或是一個接口。
簡單工廠模式不屬於GoF四人組提出的23種設計模式,它是最簡單的工廠模式。
簡單工廠模式包含類:
-
Factory:工廠類,內部有是個精通的方法,根據參數選擇創建的對象
-
Product:抽象產品類,其作為具體產品的父類,負責定義產品的公共接口
-
ConcreteProduct:具體產品類,有多個,都是繼承與抽象產品類,工廠就是創建該類對象
2. 示例
示例源於《大話設計模式》,通過一個簡單的四則計算器來逐步的重構,最終通過簡單工廠實現一個簡單的四則計算器。
首先創建一個簡單的控制台項目,實現一個簡單的四則運算計算器功能
當提示用戶輸入兩個數字,並輸入一個四則運算符,實現計算功能
2.1 計算器V1.0
namespace Calculator
{
public class Operation
{
public static double GetResult(double numA, double numB, string oper)
{
double result = 0;
switch (oper)
{
case "+":
result = numA + numB;
break;
case "-":
result = numA - numB;
break;
case "*":
result = numA * numB;
break;
case "/":
result = numB != 0 ? numA / numB : 0;
break;
}
return result;
}
}
//讓業務邏輯和界面邏輯分離
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("enter a number");
double numA = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("enter another number");
double numB = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("enter operation");
string oper = Console.ReadLine();
Console.WriteLine(Operation.GetResult(numA, numB, oper).ToString());
Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine("error:" + e.Message);
Console.ReadKey();
}
}
}
}
2.2 計算器V2.0
計算器V1.0中使用類對業務邏輯進行封裝了
但是你若是要是想要添加一個新的運算符則要對Operation
類進行修改
其實這樣是不安全的,萬一你添加新的運算符的時候把原來的運算符的操作代碼修改錯了
這樣豈不是對項目代碼很不安全!
所以你可以把所有的運算符分別單獨定義一個類,這樣你就可以隨意添加和修改某一個新的運算符
但是這時候問題又來了,主程序怎么判斷要建哪一個運算符的對象
所以需要一個Factory
類來判斷建什么對象
在工廠類中,我們使用里氏原則(子類對象賦值給父類變量)。
即:先聲明一個父類對象的變量,根據用戶輸入判斷新建什么具體的運算符對象
工廠類,只要有一個靜態方法,根據條件的返回一個各種方法的父類對象。
代碼示例
//聲明Operation基類(使用接口也可以,使用抽象類也可以)
public abstract class Operation
{
private double _numA;
private double _numB;
public double NumA { get; set; }
public double NumB { get; set; }
public abstract double GetResult()
}
//加法運算符
public class OperationAdd : Operation
{
public override double GetResult()
{
double result = 0;
result = this.NumA + this.NumB;
return result;
}
}
//減法運算符
public class OperationSub : Operation
{
public override double GetResult()
{
double result = 0;
result = this.NumA - this.NumB;
return result;
}
}
//乘法運算符
public class OperationMul : Operation
{
public override double GetResult()
{
double result = 0;
result = this.NumA * this.NumB;
return result;
}
}
//除法運算符
public class OperationDiv : Operation
{
public override double GetResult()
{
double result = 0;
if (this.NumB == 0)
{
throw new Exception("除數不為0!");
}
result = this.NumA / this.NumB;
return result;
}
}
//工廠類
public class OperationFactory
{
public static Operation CreateOperation(string operation)
{
Operation oper = null;
switch (operation)
{
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
//主程序
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("enter operation");
string operation = Console.ReadLine();
Operation oper = OperationFactory.CreateOperation(operation);
Console.WriteLine("enter a number");
oper.NumA = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("enter another number");
oper.NumB = Convert.ToDouble(Console.ReadLine());
double result = oper.GetResult();
Console.WriteLine($"運算結果:{result.ToString()}");
Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine("error:" + e.Message);
Console.ReadKey();
}
}
}
2.3 程序類圖
3. 總結分析
-
優點:簡單工廠模式,使用工廠對象創建具體的產品對象,從而使得對象的使用和創建過程進行的分離。
客戶端不需要關注對象是誰創建的,只要通過工廠中靜態方法就可以直接獲取其需要的對象
-
缺點:工廠類中需要選擇創建具體某個對象,所以一旦添加新的產品則必須要對工廠中的選擇邏輯進行修改,違背了開閉原則!
-
適應場合:產品類相對較少的情況,使用簡單工廠創建產品對象,這樣即實現了生產者與消費者的分離,也不會在工廠類中出現太復雜的判斷邏輯!