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

.NET 設計模式(6):原型模式——以複製取代創建的動態物件生成術

     編輯:關於.NET

前言:當「new」不再是最佳選擇

工廠模式雖封裝了創建邏輯,但每新增一種產品類型,就需新增對應的工廠類別,導致平行階層膨脹。原型模式(Prototype Pattern)另闢蹊徑:用原型實例指定創建物件的種類,並透過拷貝這些原型創建新物件(GoF)。它不問「怎麼構建」,只問「複製哪個」,極適合「產品類型動態、大量相似實例」的場景。

核心機制:淺拷貝 vs 深拷貝

.NET 提供兩種原生拷貝機制:

特性淺拷貝深拷貝
方法Object.MemberwiseClone()序列化反序列化 / 手動遞迴複製
值型別逐位複製逐位複製
參考型別複製參考(共用同一物件)遞迴複製被參考物件
效能極快較慢(序列化開銷)
適用場景純值型別欄位、不可變物件包含可變參考型別欄位

實戰案例:動態調色盤系統

階段 1:傳統工廠方法的困境

每種顏色一個類別 + 一個工廠類別。顏色數量動態增減時,類別爆炸。

工廠方法類別爆炸

階段 2:原型模式重構

關鍵設計:單一 ConcreteColorPrototype 類別以參數化 RGB 值表示所有顏色,透過 Clone() 複製。


[Serializable]
public abstract class ColorPrototype {
    public abstract ColorPrototype Clone(bool deep);
}

[Serializable]
public class ConcreteColorPrototype : ColorPrototype {
    private int _red, _green, _blue;
    public ConcreteColorPrototype(int r, int g, int b) { _red = r; _green = g; _blue = b; }
    
    public override ColorPrototype Clone(bool deep) {
        return deep ? CreateDeepCopy() : (ColorPrototype)MemberwiseClone();
    }
    
    // 深拷貝實現
    private ColorPrototype CreateDeepCopy() {
        using (var ms = new MemoryStream()) {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, this);
            ms.Position = 0;
            return (ColorPrototype)formatter.Deserialize(ms);
        }
    }
    
    public void Display(string name) => 
        Console.WriteLine($"{name}'s RGB Values are: {_red},{_green},{_blue}");
}

原型管理器:動態註冊與查找


public class ColorManager {
    private readonly Hashtable _prototypes = new Hashtable();
    public ColorPrototype this[string name] {
        get => (ColorPrototype)_prototypes[name];
        set => _prototypes.Add(name, value);
    }
}

原型管理器結構

客戶端:運行期動態組合


class App {
    public static void Main() {
        var manager = new ColorManager();
        // 初始化基礎原型(可從配置檔、資料庫載入)
        manager["red"] = new ConcreteColorPrototype(255, 0, 0);
        manager["green"] = new ConcreteColorPrototype(0, 255, 0);
        manager["blue"] = new ConcreteColorPrototype(0, 0, 255);
        // 動態新增語義化顏色(無需新增類別!)
        manager["angry"] = new ConcreteColorPrototype(255, 54, 0);
        manager["peace"] = new ConcreteColorPrototype(128, 211, 128);
        manager["flame"] = new ConcreteColorPrototype(211, 34, 20);
        
        // 使用:複製原型而非 new
        var c1 = (ConcreteColorPrototype)manager["red"].Clone(false);
        c1.Display("red");
        
        var c2 = (ConcreteColorPrototype)manager["peace"].Clone(true); // 深拷貝
        c2.Display("peace");
    }
}

原型模式的四大核心優勢

  1. 消除平行工廠階層:無需 ColorFactory、RedFactory 等,直接複製原型
  2. 動態增減產品類型:運行期向管理器註冊/移除原型,支援外掛式架構
  3. 簡化複雜物件創建:預設參數、預設狀態封裝在原型中,複製即得
  4. 符合依賴倒置原則:管理器依賴抽象 ColorPrototype,具體原型亦依賴抽象

依賴倒置關係

.NET 生態中的原型應用

  • ICloneable 介面:標準化克隆契約(雖因淺/深拷貝語義模糊被部分指南不推薦)
  • DataTable.Clone() / Copy():複製結構 vs 複製結構+資料
  • Expression 樹的 Visit 模式:本質是原型式的樹結構複製與修改
  • 實體框架的實體複製、DTO 映射庫(AutoMapper 等)內部大量使用拷貝機制
  • 遊戲開發中 Instantiate(prefab):Unity 的 Prefab 系統即原型模式經典應用

實作陷阱與最佳實踐

  1. 淺拷貝陷阱:含 List<T>、自訂類別欄位時,複製出的實例共用子物件,修改一方影響另一方 → 必須深拷貝或實作 ICloneable 時手動複製集合
  2. 序列化深拷貝限制:所有類別必須標記 [Serializable];不支援委派、事件、非序列化欄位;效能較差 → 高效能場景考慮 Expression 樹編譯複製或手寫複製邏輯
  3. 原型管理器線程安全:多執行緒環境下註冊/查找需加鎖或用 ConcurrentDictionary
  4. 循環引用處理:序列化深拷貝自動處理循環引用,手動複製需維護 Dictionary 追蹤已複製物件
  5. 不可變物件優化:若原型完全不可變,可直接回傳自身(單例式原型),避免複製開銷

適用場景判斷

以下情況優先考慮原型模式:

  • 系統應獨立於產品創建、構成、表示細節
  • 實例化類別在運行期指定(動態載入組件、外掛系統)
  • 避免建立與產品階層平行的工廠階層
  • 物件狀態組合有限(如報表模板、遊戲實體預設屬性),建立原型比手動實例化更便捷
  • 大量相似物件創建,效能敏感(淺拷貝極快)

總結

原型模式以「複製」取代「構建」,將創建知識從「如何一步步建構」轉移為「複製哪個範本」。它不解決「建構複雜物件」的問題(那是建造者的事),而是解決「大量相似、動態類型、避免工廠膨脹」的問題。在 .NET 中,配合序列化或 MemberwiseClone,原型模式是實現物件模板、預設值管理、運行期類型擴展的利器。記住:當你發現自己在寫大量「參數化建構子」或「工廠方法只是單純 new 不同參數」時,原型模式可能是更好的選擇。

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