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

C# 裝飾模式完全指南:動態組合行為與開閉原則的完美實踐

     編輯:關於C#

前言

當需要為物件動態添加職責,且希望比繼承更靈活、避免類別爆炸時,裝飾模式是首選:將物件包裝在裝飾者中,裝飾者實作相同介面,持有被裝飾物件參考,轉發呼叫並在前後插入額外邏輯。多個裝飾者可疊加組合,形成靈活的行為管道。本文以訊息系統為例,展示如何用 CheckUserWrapper(用戶驗證)、CheckInputWrapper(輸入驗證)動態裝飾 SqlMessage,並支援雙重裝飾組合。

模式結構與四大角色

  • Component(抽象構件):AbstractMessage,定義 Get()、Insert() 共同介面。
  • ConcreteComponent(具體構件):SqlMessage、XmlMessage,核心業務實作。
  • Decorator(抽象裝飾者):AbstractMessageWrapper,實作 AbstractMessage,持有 _abstractMessage 參考,預設轉發呼叫。
  • ConcreteDecorator(具體裝飾者):CheckUserWrapper、CheckInputWrapper,覆寫方法在轉發前後添加邏輯。
裝飾模式類別圖

核心程式碼機制深度解析

1. 抽象構件與具體構件

public abstract class AbstractMessage
{
    public abstract List<MessageModel> Get();
    public abstract bool Insert(MessageModel mm);
}

public class SqlMessage : AbstractMessage
{
    public override List<MessageModel> Get()
    {
        var l = new List<MessageModel>();
        l.Add(new MessageModel("SQL方式獲取Message", DateTime.Now));
        return l;
    }
    public override bool Insert(MessageModel mm) { return true; }
}

2. 抽象裝飾者:透明轉發基礎

public abstract class AbstractMessageWrapper : AbstractMessage
{
    private AbstractMessage _abstractMessage;

    public AbstractMessageWrapper(AbstractMessage abstractMessage)
    {
        this._abstractMessage = abstractMessage;
    }

    public override List<MessageModel> Get() => _abstractMessage.Get();
    public override bool Insert(MessageModel mm) => _abstractMessage.Insert(mm);
}

關鍵:預設實作完全透明轉發,具體裝飾者只需覆寫需增強的方法。

3. 具體裝飾者:橫切關注點封裝

CheckUserWrapper(用戶驗證裝飾):

public class CheckUserWrapper : AbstractMessageWrapper
{
    public CheckUserWrapper(AbstractMessage abstractMessage) : base(abstractMessage) { }

    public override List<MessageModel> Get()
    {
        var l = base.Get(); // 先取得核心結果
        foreach (var mm in l)
            mm.Message += "(經過用戶驗證)"; // 後處理:標記
        return l;
    }
    public override bool Insert(MessageModel mm)
    {
        // 前處理:驗證邏輯(此處略)
        return base.Insert(mm);
    }
}

CheckInputWrapper(輸入驗證裝飾):結構相同,標記「經過輸入驗證」。

4. 客戶端:動態組合與疊加


AbstractMessage message = new SqlMessage();

// 單一裝飾
var amr = new CheckUserWrapper(message);
Response.Write(amr.Get()[0].Message); // SQL方式獲取Message(經過用戶驗證)

var amr2 = new CheckInputWrapper(message);
Response.Write(amr2.Get()[0].Message); // SQL方式獲取Message(經過輸入驗證)

// 雙重裝飾:順序很重要!
var amr3 = new CheckUserWrapper(message);       // 內層:用戶驗證
var amr4 = new CheckInputWrapper(amr3);         // 外層:輸入驗證
Response.Write(amr4.Get()[0].Message); 
// SQL方式獲取Message(經過用戶驗證)(經過輸入驗證)

執行結果驗證

SQL方式獲取Message(經過用戶驗證) 2007-5-13 19:34:01
SQL方式獲取Message(經過輸入驗證) 2007-5-13 19:34:01
SQL方式獲取Message(經過用戶驗證)(經過輸入驗證) 2007-5-13 19:34:01

完美驗證:裝飾者疊加順序決定執行順序(外層先執行前處理、內層後執行後處理),行為靈活組合。

裝飾模式 vs 繼承 vs 策略模式

維度繼承策略模式裝飾模式
靈活度編譯期固定執行期可換演算法執行期可疊加多重行為
組合方式Is-A (單一)Has-A (單一策略)Has-A (多層包裝)
擴展性類別爆炸風險新增策略類別新增裝飾類別,任意組合
適用場景核心身份固定演算法整體替換橫切關注點疊加

進階應用與最佳實務

裝飾者順序語義:洋蔥模型

new Outer(new Inner(core)) 執行流程:

Outer.Before → Inner.Before → Core → Inner.After → Outer.After

如:Logging(Transaction(Authorization(Core))) → 日誌記錄交易邊界,交易包含授權檢查。

.NET 生態中的裝飾模式實踐

  • Stream 裝飾鏈:FileStream → BufferedStream → CryptoStream → GZipStream → StreamReader,經典裝飾模式應用。
  • ASP.NET Core Middleware:UseA → UseB → UseC 本質是裝飾 RequestDelegate 管道。
  • HttpClient DelegatingHandler:HttpMessageHandler 裝飾鏈,支援重試、日誌、驗證、快取。
  • Entity Framework 攔截器:DbCommandInterceptor 裝飾命令執行。
  • Polly PolicyWrap:Policy.Wrap(PolicyA, PolicyB) 組合重試、斷路器、超時策略。

裝飾者與介面隔離

  • 若 AbstractMessage 方法過多,裝飾者需全部轉發(即使不關心)。
  • 解決:拆分介面 IMessageReader、IMessageWriter,裝飾者只實作關心介面,或使用「空物件模式」預設實作。

避免過度裝飾

  • 超過 3-4 層裝飾難以除錯,考慮合併為單一裝飾者或改用管道/中介者模式。
  • 裝飾者不應破壞被裝飾物件的不變條件(如:Insert 成功才標記驗證通過)。

優缺點總結

優點

  • 比繼承靈活:執行期動態組合、疊加、移除行為。
  • 符合單一職責:每個裝飾者封裝單一橫切關注點。
  • 符合開閉原則:新增裝飾者無需修改核心或既有裝飾者。
  • 支援任意排列組合:N 個裝飾者可產生 2^N 種行為組合。

缺點

  • 小物件眾多:大量裝飾者實例增加記憶體/GC 壓力。
  • 除錯困難:堆疊追蹤包含多層轉發,需工具支援(如 VS「裝飾者展開」)。
  • 型別身份改變:decorated is SqlMessage 為 false,需用模式匹配或介面判斷。
  • 雙向關聯風險:若裝飾者需回呼核心,易產生循環引用。

總結

裝飾模式以「包裝轉發 + 前後增強」實現物件行為的動態疊加組合,是「組合優於繼承」原則的教科書級應用。本範例以用戶驗證、輸入驗證雙重裝飾 SQL 訊息查詢為例,完整展示了抽象構件、具體構件、抽象裝飾者、具體裝飾者四角色協作,驗證了裝飾順序決定執行順序的洋蔥模型語義。實務中,從 Stream 處理管道、HTTP Middleware、重試策略組合到 AOP 攔截器,裝飾模式無處不在。掌握其核心——「透明轉發基礎、單一職責增強、任意疊加組合、順序語義明確」,能讓你在設計「橫切關注點模組化、行為管道可配置、核心邏輯純淨」的系統時,構建出極具彈性與可維護性的架構。


參考資源:DoFactory Decorator Pattern

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