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

C# 中介者模式深度解析:解耦物件間複雜交互的核心藝術

     編輯:關於C#

前言

在複雜系統中,多個物件之間往往存在錯綜複雜的相互引用與通訊關係:A 呼叫 B、B 通知 C、C 又回調 A……這種「網狀耦合」導致系統難以維護、擴展與測試。中介者模式透過引入一個「中介者」物件,將多對多的交互關係轉化為一對多的「星狀結構」:所有同事物件不再直接引用彼此,而是透過中介者轉發訊息。本文以訊息傳遞系統為例,完整展示中介者模式如何封裝用戶間的發送/接收邏輯,實現鬆散耦合。

模式結構與四大角色

  • Mediator(抽象中介者):AbstractMessageMediator,定義 Register() 註冊同事、Send() 轉發訊息介面。
  • ConcreteMediator(具體中介者):MessageMediator,維護同事字典 Dictionary<string, AbstractMessage>,實作註冊與路由邏輯:根據接收者 ID 找到對應同事並呼叫其 Insert()。
  • Colleague(抽象同事):AbstractMessage,持有中介者參考,提供 Send(to, mm) 供客戶端呼叫(轉發給中介者)、Insert(from, mm) 供中介者回呼(實際接收處理)。
  • ConcreteColleague(具體同事):SqlMessage、XmlMessage,實作不同儲存方式的 Insert(),分別代表 SQL 與 XML 用戶。
中介者模式類別圖

核心程式碼機制深度解析

1. 抽象中介者:定義協調契約

public abstract class AbstractMessageMediator
{
    public abstract void Register(AbstractMessage abstractMessage);
    public abstract string Send(string from, string to, MessageModel mm);
}

2. 具體中介者:路由核心與同事管理

public class MessageMediator : AbstractMessageMediator
{
    private Dictionary<string, AbstractMessage> _dictionary = new Dictionary<string, AbstractMessage>();

    public override void Register(AbstractMessage abstractMessage)
    {
        if (!_dictionary.ContainsKey(abstractMessage.UserId))
            _dictionary.Add(abstractMessage.UserId, abstractMessage);
        abstractMessage.AbstractMessageMediator = this; // 關鍵:反向注入中介者參考
    }

    public override string Send(string from, string to, MessageModel mm)
    {
        AbstractMessage abstractMessage = _dictionary[to];
        if (abstractMessage != null)
            return abstractMessage.Insert(from, mm); // 路由至目標同事
        return null;
    }
}

關鍵設計:

  • 字典以 UserId 為鍵,實現 O(1) 查找接收者。
  • Register() 中將 this 注入同事的 AbstractMessageMediator 屬性,建立雙向關聯(同事→中介者)。
  • Send() 封裝路由邏輯:發送者只需知道接收者 ID,不知曉接收者具體類型與儲存方式。

3. 抽象同事:統一通訊介面

public abstract class AbstractMessage
{
    private AbstractMessageMediator _abstractMessageMediator;
    private string _userId;

    public AbstractMessage(string userId) { this._userId = userId; }
    public string UserId { get { return _userId; } }

    public AbstractMessageMediator AbstractMessageMediator 
    { 
        get { return _abstractMessageMediator; } 
        set { _abstractMessageMediator = value; } 
    }

    // 客戶端呼叫:發送訊息給指定用戶
    public string Send(string to, MessageModel mm)
    {
        return _abstractMessageMediator.Send(_userId, to, mm);
    }

    // 中介者回呼:實際接收並處理訊息
    public abstract string Insert(string from, MessageModel mm);
}

雙向通訊設計精髓:

  • Send():同事主動發起,委派給中介者路由。
  • Insert():中介者路由後回呼,同事被動接收處理。

4. 具體同事:差異化處理邏輯

public class SqlMessage : AbstractMessage
{
    public SqlMessage(string userId) : base(userId) { }
    public override string Insert(string from, MessageModel mm)
    {
        return "Sql方式插入Message(" + from + "發送給" + base.UserId + ")"
             + " - 內容:" + mm.Message
             + " - 時間:" + mm.PublishTime.ToString();
    }
}
// XmlMessage 結構相同,僅前綴不同

5. 客戶端:組裝與使用

AbstractMessageMediator mediator = new MessageMediator();

AbstractMessage user1 = new SqlMessage("user1");
AbstractMessage user2 = new SqlMessage("user2");
AbstractMessage user3 = new XmlMessage("user3");
AbstractMessage user4 = new XmlMessage("user4");

mediator.Register(user1);
mediator.Register(user2);
mediator.Register(user3);
mediator.Register(user4);

// user1 → user2 (SQL→SQL)
Response.Write(user1.Send("user2", new MessageModel("你好!", DateTime.Now)));
// user3 → user4 (XML→XML)
Response.Write(user3.Send("user4", new MessageModel("吃了嗎?", DateTime.Now)));

執行結果分析

Sql方式插入Message(user1發送給user2) - 內容:你好! - 時間:2007-5-19 23:43:19
Sql方式插入Message(user2發送給user1) - 內容:我不好! - 時間:2007-5-19 23:43:19
Xml方式插入Message(user3發送給user4) - 內容:吃了嗎? - 時間:2007-5-19 23:43:19
Xml方式插入Message(user4發送給user3) - 內容:沒吃,你請我? - 時間:2007-5-19 23:43:19

結果驗證:

  • 發送者完全不知曉接收者使用 SQL 或 XML 儲存。
  • 中介者根據接收者 ID 路由至正確同事實例。
  • 新增用戶類型(如 JsonMessage)只需實作 AbstractMessage 並註冊,零修改既有程式碼。

進階應用與設計考量

中介者與觀察者模式的關係

  • 觀察者:一對多廣播,發送者不知曉接收者,接收者訂閱主題。
  • 中介者:多對多協調,中介者知曉所有參與者並控制流程,常包含路由、過濾、聚合等邏輯。
  • 兩者可結合:中介者內部使用觀察者模式分發事件給同事。

避免「上帝類別」反模式

中介者易膨脹為包含所有業務邏輯的「上帝類別」。最佳實務:

  • 中介者僅負責「路由與協調」,具體業務邏輯保留在同事類別中。
  • 複雜協調邏輯可拆分為多個中介者,或使用「命令模式」封裝操作由中介者執行。
  • 考慮使用介面隔離:IMediator 只暴露必要方法給同事。

同事間直接通訊 vs 中介者轉發

  • 若同事間關係簡單、固定,直接引用可能更清晰(YAGNI 原則)。
  • 當同事數量多、關係動態、需集中控制(如權限檢查、日誌、事務)時,中介者價值凸顯。

優缺點總結

優點

  • 減少物件間直接依賴,降低耦合度。
  • 集中管理交互邏輯,易於修改、擴展、監控。
  • 同事類別職責單一,易於複用與測試。
  • 支援動態新增/移除同事(聊天室上下線、插件系統)。

缺點

  • 中介者類別可能過於複雜(需謹慎拆分職責)。
  • 間接層增加,可能影響效能(通常可忽略)。
  • 不適用於「物件間無共同協調邏輯」的簡單場景。

總結

中介者模式以「星狀結構」取代「網狀耦合」,將物件間複雜交互封裝於中介者內部,實現同事物件的鬆散耦合與獨立演化。本範例以跨儲存類型(SQL/XML)的用戶訊息傳遞為例,完整展示了註冊機制、雙向通訊介面、路由邏輯與客戶端組裝的全流程。實務中廣泛應用於:GUI 對話框協調(按鈕、輸入框、列表互動)、聊天室伺服器、工作流引擎協調器、MVC 架構中的 Controller、微服務 API Gateway 路由等場景。掌握中介者模式,能讓你在面對「多物件複雜協作」的系統設計挑戰時,構建出清晰可控、易於擴展的架構。


參考資源:DoFactory Mediator Pattern

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