首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 設計模式實戰:簡單工廠模式完整解析與多種實現方式

     編輯:關於C語言

從「自己做飯」到「點餐吃飯」:封裝對象創建變化,降低耦合

簡單工廠模式 (Simple Factory) 又稱靜態工廠方法模式,雖非 GoF 23 種經典模式之一,但極其實用且普及。本文通過「吃飯」生活場景,對比無工廠/有工廠代碼,展示標準實現、反射實現、.NET Framework 內置案例 (Encoding.GetEncoding),並深度分析優缺點與適用場景。

場景還原:自己做飯 vs 點餐

// 無工廠:客戶類直接 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(); // 輸出:一份西紅柿炒蛋!

標準結構 (UML 角色)

  • Factory (FoodSimpleFactory):靜態工廠方法 CreateFood(),根據參數返回抽象產品實例。
  • Abstract Product (Food):抽象類/接口,定義 Print() 等公共行為。
  • Concrete Products:TomatoScrambledEggs、ShreddedPorkWithPotatoes 等具體實現。
  • Client (Customer):調用工廠獲取產品,不知具體類名。

反射實現:開閉原則更友好

新增產品無需修改工廠類,只需確保類名規約 (如命名空間 + 類名) 並註冊/約定:

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);

.NET Framework 內置案例:Encoding.GetEncoding

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 解決「新增編碼需修改工廠」的問題,因編碼標準相對穩定,這種妥協可接受。

優點總結

  • 分離職責:客戶不負責創建,只負責使用。
  • 代碼復用:工廠邏輯集中,多客戶共用。
  • 簡單易懂:靜態方法調用,無額外接口/繼承複雜度。

缺點與局限

  • 違反開閉原則:新增產品必須修改工廠類 (增加 if/switch 分支)。
  • 工廠職責過重:所有創建邏輯集中,工廠類膨脹,維護困難。
  • 單點故障:工廠掛了全系統無法創建對象。

適用場景

  1. 工廠創建的對象較少、固定 (如 Encoding、數據庫連接類型)。
  2. 客戶只知道參數,不關心創建細節。
  3. 作為更複雜模式 (工廠方法、抽象工廠) 的過渡/簡化版。

進階:工廠方法模式解決缺點

將工廠方法下放到子類,每個具體產品對應一個具體工廠,新增產品只需新增工廠類,不修改現有代碼,完美符合開閉原則。這是下一篇將講解的內容。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved