簡單工廠模式 (Simple Factory) 又稱靜態工廠方法模式,雖非 GoF 23 種經典模式之一,但極其實用且普及。本文通過「吃飯」生活場景,對比無工廠/有工廠代碼,展示標準實現、反射實現、.NET Framework 內置案例 (Encoding.GetEncoding),並深度分析優缺點與適用場景。
// 無工廠:客戶類直接 new 具體菜品,想吃新菜必須改客戶代碼 → 高耦合
public class Customer {
public static Food Cook(string type) {
if (type == "西紅柿炒蛋") return new TomatoScrambledEggs();
else if (type == "土豆肉絲") return new ShreddedPorkWithPotatoes();
return null;
}
}
// 有簡單工廠:創建邏輯移至 FoodSimpleFactory,客戶只管消費
public class FoodSimpleFactory {
public static Food CreateFood(string type) {
if (type == "土豆肉絲") return new ShreddedPorkWithPotatoes();
else if (type == "西紅柿炒蛋") return new TomatoScrambledEggs();
return null;
}
}
// 客戶調用
Food food = FoodSimpleFactory.CreateFood("西紅柿炒蛋");
food.Print(); // 輸出:一份西紅柿炒蛋!
CreateFood(),根據參數返回抽象產品實例。Print() 等公共行為。TomatoScrambledEggs、ShreddedPorkWithPotatoes 等具體實現。新增產品無需修改工廠類,只需確保類名規約 (如命名空間 + 類名) 並註冊/約定:
public class FruitFactory {
private static FruitFactory _instance = new FruitFactory();
public static FruitFactory Instance => _instance;
public IFruit MakeFruit(string name) { // name = "ConsoleApplication1.Orange"
try {
Type t = Type.GetType(name, true);
return (IFruit)Activator.CreateInstance(t);
} catch (TypeLoadException e) {
Console.WriteLine("Unknown fruit: " + e.Message);
return null;
}
}
}
// 使用
string fruitName = Console.ReadLine(); // 輸入 "Orange"
FruitFactory.Instance.MakeFruit("ConsoleApplication1." + fruitName);
System.Text.Encoding 就是簡單工廠的變體:抽象產品類自身充當工廠,GetEncoding(int codepage) 內部 switch 返回具體編碼實例 (UTF8Encoding、UnicodeEncoding、SBCSCodePageEncoding 等)。
// 簡化版邏輯
public static Encoding GetEncoding(int codepage) {
// 緩存查找...
switch (codepage) {
case 0: return Default;
case 1200: return Unicode; // UTF-16 LE
case 1201: return BigEndianUnicode;
case 65001: return UTF8;
case 1252: return Latin1;
default:
Encoding e = GetEncodingCodePage(codepage); // 系統代碼頁
if (e == null) e = GetEncodingRare(codepage); // 罕見編碼
return e;
}
}
微軟通過 default 分支委託給 GetEncodingRare 解決「新增編碼需修改工廠」的問題,因編碼標準相對穩定,這種妥協可接受。
Encoding、數據庫連接類型)。將工廠方法下放到子類,每個具體產品對應一個具體工廠,新增產品只需新增工廠類,不修改現有代碼,完美符合開閉原則。這是下一篇將講解的內容。