設計模式(十八)行為型:中介者模式詳解

設計模式(十八)行為型:中介者模式詳解

中介者模式(Mediator Pattern)是 GoF 23 種設計模式中的行為型模式之一,其核心價值在于通過引入一個中介者對象來封裝一組對象之間的交互,從而降低對象間的耦合度,使對象不必顯式地相互引用,實現松耦合的協作關系。它將原本“網狀”的多對多通信結構轉化為“星型”結構,所有對象僅與中介者通信,由中介者負責協調和轉發消息。中介者模式廣泛應用于圖形用戶界面(GUI)組件交互、聊天室系統、航空交通管制、多玩家游戲協調、微服務編排、事件總線(Event Bus)等需要集中管理復雜交互邏輯的場景,是構建可維護、可擴展、高內聚低耦合系統的架構利器。

一、詳細介紹

中介者模式解決的是“多個對象之間存在復雜的、動態的、多對多的交互關系,導致系統結構混亂、難以理解、修改和擴展”的問題。在傳統設計中,對象(如窗口中的按鈕、文本框、下拉框)為了響應彼此的狀態變化,會直接持有對方的引用并調用其方法。這導致:

  • 緊耦合:對象之間相互依賴,修改一個對象可能影響多個其他對象。
  • 高復雜度:交互邏輯分散在各個對象中,難以維護。
  • 難以復用:對象無法獨立使用,必須依賴特定的協作環境。
  • 擴展困難:新增對象或交互邏輯需要修改大量現有代碼。

中介者模式的核心思想是:“將交互邏輯集中化”,引入一個“中介者”(Mediator)作為所有交互的協調中心。各個協作對象(Colleague)不再直接通信,而是將請求發送給中介者,由中介者根據當前系統狀態決定如何處理或轉發該請求。

該模式包含以下核心角色:

  • Mediator(中介者接口):定義同事對象用來與中介者通信的接口,通常包含一個或多個通知方法(如 notify(sender, event))。
  • ConcreteMediator(具體中介者):實現 Mediator 接口,知道所有具體同事對象,并負責協調它們之間的交互。它維護同事對象的引用,并在收到通知時執行相應的協調邏輯。
  • Colleague(同事類):定義同事對象的基類或接口,持有對中介者的引用。同事對象通過中介者與其他同事通信。
  • ConcreteColleague(具體同事類):繼承或實現 Colleague,在自身狀態發生變化時,通過中介者發出通知,而不直接調用其他同事的方法。

中介者模式的關鍵優勢:

  • 降低耦合度:同事對象之間無直接依賴,僅依賴中介者。
  • 集中控制交互邏輯:交互邏輯集中在中介者中,易于理解、修改和擴展。
  • 提高可復用性:同事對象可以獨立于其他同事被復用。
  • 支持動態配置:中介者可以在運行時動態改變對象間的協作方式。
  • 簡化對象設計:同事對象無需維護與其他對象的引用。

與“觀察者模式”相比,中介者關注多對象間的雙向協調,觀察者關注一對多的單向狀態通知;與“命令模式”相比,命令封裝單個請求,中介者協調多個對象的協作;與“外觀模式”相比,外觀為子系統提供統一接口,中介者管理子系統內部組件的交互

中介者模式適用于:

  • 對象間交互復雜且多變。
  • 交互邏輯需要集中管理。
  • 希望提高對象的獨立性和可復用性。

二、中介者模式的UML表示

以下是中介者模式的標準 UML 類圖:

implements
implements
implements
knows
knows
uses
uses
?interface?
Mediator
+notify(sender: Colleague, event: String)
ConcreteMediator
-colleague1: ConcreteColleague1
-colleague2: ConcreteColleague2
+notify(sender: Colleague, event: String)
Colleague
-mediator: Mediator
+send(event: String)
+receive(event: String)
ConcreteColleague1
+send(event: String)
+receive(event: String)
ConcreteColleague2
+send(event: String)
+receive(event: String)

圖解說明

  • Mediator 定義通知接口。
  • ConcreteMediator 知道所有具體同事,并實現協調邏輯。
  • Colleague 持有中介者引用,通過 send() 發送事件。
  • 同事對象通過中介者間接通信。

三、一個簡單的Java程序實例及其UML圖

以下是一個 GUI 對話框的示例,包含“登錄”按鈕、“用戶名”文本框、“密碼”文本框和“記住我”復選框。它們之間的交互由中介者協調。

Java 程序實例
// 中介者接口
interface Mediator {void notify(Component sender, String event);
}// 抽象同事組件
abstract class Component {protected Mediator mediator;public Component(Mediator mediator) {this.mediator = mediator;}public void send(String event) {mediator.notify(this, event);}public abstract void receive(String event);
}// 具體同事:按鈕
class Button extends Component {private boolean enabled = false;private String name;public Button(Mediator mediator, String name) {super(mediator);this.name = name;}public void setEnabled(boolean enabled) {this.enabled = enabled;System.out.println("🔘 [" + name + "] 按鈕狀態: " + (enabled ? "啟用" : "禁用"));}public boolean isEnabled() {return enabled;}@Overridepublic void receive(String event) {if ("enable".equals(event)) {setEnabled(true);} else if ("disable".equals(event)) {setEnabled(false);}}
}// 具體同事:文本框
class TextBox extends Component {private String text = "";private String name;public TextBox(Mediator mediator, String name) {super(mediator);this.name = name;}public void setText(String text) {this.text = text;System.out.println("📝 [" + name + "] 輸入: \"" + text + "\"");// 文本變化時通知中介者send("textChanged");}public String getText() {return text;}@Overridepublic void receive(String event) {// 文本框通常不接收外部控制事件System.out.println("📝 [" + name + "] 收到事件: " + event + " (忽略)");}
}// 具體同事:復選框
class Checkbox extends Component {private boolean checked = false;private String name;public Checkbox(Mediator mediator, String name) {super(mediator);this.name = name;}public void setChecked(boolean checked) {this.checked = checked;System.out.println("?? [" + name + "] 狀態: " + (checked ? "選中" : "未選中"));// 狀態變化時通知中介者send("checkboxChanged");}public boolean isChecked() {return checked;}@Overridepublic void receive(String event) {// 復選框通常不接收外部控制事件System.out.println("?? [" + name + "] 收到事件: " + event + " (忽略)");}
}// 具體中介者:登錄對話框
class LoginDialogMediator implements Mediator {private Button loginButton;private TextBox usernameBox;private TextBox passwordBox;private Checkbox rememberMeBox;public LoginDialogMediator(Button loginButton, TextBox usernameBox, TextBox passwordBox, Checkbox rememberMeBox) {this.loginButton = loginButton;this.usernameBox = usernameBox;this.passwordBox = passwordBox;this.rememberMeBox = rememberMeBox;}@Overridepublic void notify(Component sender, String event) {System.out.println("🔄 中介者收到事件: [" + sender.getClass().getSimpleName() + "] 發出 '" + event + "'");// 根據發送者和事件類型協調交互if (sender == usernameBox && "textChanged".equals(event)) {checkLoginButton();} else if (sender == passwordBox && "textChanged".equals(event)) {checkLoginButton();} else if (sender == rememberMeBox && "checkboxChanged".equals(event)) {if (rememberMeBox.isChecked()) {System.out.println("💡 用戶選擇記住登錄狀態");} else {System.out.println("💡 用戶取消記住登錄狀態");}}}// 檢查是否啟用登錄按鈕private void checkLoginButton() {boolean usernameFilled = usernameBox.getText().trim().length() > 0;boolean passwordFilled = passwordBox.getText().trim().length() > 0;if (usernameFilled && passwordFilled) {loginButton.send("enable"); // 通過中介者啟用按鈕} else {loginButton.send("disable");}}// 提供獲取組件的方法(可選,用于初始化)public Button getLoginButton() { return loginButton; }public TextBox getUsernameBox() { return usernameBox; }public TextBox getPasswordBox() { return passwordBox; }public Checkbox getRememberMeBox() { return rememberMeBox; }
}// 客戶端使用示例
public class MediatorPatternDemo {public static void main(String[] args) {System.out.println("🔐 登錄對話框 - 中介者模式示例\n");// 創建同事對象Button loginButton = new Button(null, "登錄"); // 初始中介者為 nullTextBox usernameBox = new TextBox(null, "用戶名");TextBox passwordBox = new TextBox(null, "密碼");Checkbox rememberMeBox = new Checkbox(null, "記住我");// 創建中介者并注入同事對象LoginDialogMediator mediator = new LoginDialogMediator(loginButton, usernameBox, passwordBox, rememberMeBox);// 將中介者注入到同事對象中loginButton.mediator = mediator;usernameBox.mediator = mediator;passwordBox.mediator = mediator;rememberMeBox.mediator = mediator;// 初始狀態:登錄按鈕應禁用System.out.println("\n--- 初始化 ---");loginButton.send("disable");// 模擬用戶輸入System.out.println("\n--- 用戶輸入用戶名 ---");usernameBox.setText("alice");System.out.println("\n--- 用戶輸入密碼 ---");passwordBox.setText("secret123");// 此時登錄按鈕應被啟用System.out.println("\n? 用戶名和密碼已填寫,登錄按鈕已啟用");// 模擬取消記住我System.out.println("\n--- 用戶取消記住我 ---");rememberMeBox.setChecked(false);// 模擬清空密碼System.out.println("\n--- 用戶清空密碼 ---");passwordBox.setText("");// 登錄按鈕應被禁用System.out.println("\n? 密碼已清空,登錄按鈕已禁用");}
}
實例對應的UML圖(簡化版)
implements
extends
extends
extends
has
has
has
?interface?
Mediator
+notify(sender: Component, event: String)
Component
-mediator: Mediator
+send(event: String)
+receive(event: String)
Button
-enabled: boolean
-name: String
+setEnabled(enabled: boolean)
+receive(event: String)
TextBox
-text: String
-name: String
+setText(text: String)
+receive(event: String)
Checkbox
-checked: boolean
-name: String
+setChecked(checked: boolean)
+receive(event: String)
LoginDialogMediator
-loginButton: Button
-usernameBox: TextBox
-passwordBox: TextBox
-rememberMeBox: Checkbox
+notify(sender: Component, event: String)
+checkLoginButton()

運行說明

  • LoginDialogMediator 是具體中介者,協調四個 GUI 組件。
  • 當用戶名或密碼框內容變化時,發送 textChanged 事件。
  • 中介者收到事件后,檢查兩個框是否都非空,決定啟用或禁用登錄按鈕。
  • “記住我”復選框狀態變化時,中介者記錄用戶選擇。
  • 所有交互邏輯集中在中介者中,組件之間無直接引用。

四、總結

特性說明
核心目的集中管理對象間交互,降低耦合
實現機制星型通信結構,中介者協調轉發
優點降低耦合、集中控制、提高復用性、簡化對象
缺點中介者可能變得龐大復雜(“上帝對象”)、增加系統抽象層次
適用場景GUI 交互、聊天室、游戲協調、工作流引擎、事件總線
不適用場景對象間交互簡單、交互邏輯穩定、性能極度敏感

中介者模式使用建議

  • 避免中介者過度膨脹,可將其拆分為多個子中介者。
  • 可結合“觀察者模式”實現事件通知機制。
  • 在 Java 中,java.util.Timer/TimerTask 或事件總線(如 EventBus)是中介者思想的體現。
  • 微服務中的 API Gateway 或 Service Mesh 控制平面是分布式中介者。

架構師洞見:
中介者模式是“集中式協調”與“解耦通信”的哲學體現。在現代架構中,其思想已演變為事件驅動架構(EDA)服務網格(Service Mesh)API 網關消息中間件 的核心。例如,在微服務中,服務網格的 Sidecar 代理作為中介者,管理服務間的通信、熔斷、重試;API 網關作為客戶端請求的中介者,負責路由、認證、限流;Kafka 或 RabbitMQ 作為消息中介者,解耦生產者與消費者。

未來趨勢是:中介者將與AI 編排引擎結合,AI 動態決策服務調用鏈;在邊緣計算中,邊緣網關作為本地服務的中介者;在量子網絡中,量子中繼器是量子態傳輸的中介者;在元宇宙中,虛擬世界的狀態同步依賴于強大的中介協調系統。

掌握中介者模式,有助于設計出高內聚、低耦合、易維護的復雜交互系統。作為架構師,應在面對“多對象協作”或“交互邏輯復雜”時,主動考慮引入中介者。中介者不僅是模式,更是系統治理的樞紐——它提醒我們:真正的可擴展性,來自于將“混亂的網狀通信”轉化為“有序的星型控制”,讓復雜性被封裝在單一的協調點,而非散布在系統的每一個角落。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916639.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916639.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916639.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Upload-Labs通關全攻略詳細版

前端校驗繞過:pass 01 兩種思路:1.通過抓包,修改后綴 2.前端禁用js繞過前端后綴檢驗 首先寫一個木馬,改為圖片格式GIF89a<?php eval($_POST[cmd])?>抓包之后改為PHP格式: 使用蟻劍連接木馬,第一次嘗試一直是返回數據為空,原因是沒有鏈接到木馬,于是尋找木馬地址…

C#觀察者模式示例代碼

using System; using System.Collections.Generic; using System.Threading;namespace RefactoringGuru.DesignPatterns.Observer.Conceptual {// Observer觀察者 也可以叫做訂閱者 subscriberspublic interface IObserver{// Receive update from subject// 接收來自主題的更新…

電子電子架構 --- 軟件項目的開端:裁剪

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 簡單,單純,喜歡獨處,獨來獨往,不易合同頻過著接地氣的生活,除了生存溫飽問題之外,沒有什么過多的欲望,表面看起來很高冷,內心熱情,如果你身…

Open CV圖像基本操作可莉版

Open CV圖像基本操作一、處理單個像素值訪問像素值修改像素值二、處理單個ROI區域&#xff08;自選區域&#xff09;提取 ROI修改 ROI三、 處理圖像通道通道分離通道合并四、處理整體圖像縮放圖像旋轉圖像平移圖像翻轉一、處理單個像素值 圖像是由像素組成的矩陣&#xff0c;每…

k8s:將打包好的 Kubernetes 集群鏡像推送到Harbor私有鏡像倉庫

本文介紹了在離線環境中部署Harbor鏡像倉庫的完整流程。首先通過腳本創建多個Harbor項目&#xff0c;然后使用KubeKey工具將預打包的Kubernetes鏡像(kubesphere.tar.gz)推送到Harbor倉庫。接著配置containerd以支持從私有倉庫拉取鏡像&#xff0c;包括設置TLS證書和鏡像倉庫端點…

IntelliJ IDEA中管理多版本Git子模塊的完整指南

1.背景介紹項目是父子工程。父工程XXX-ZZZ-CCC。子模塊XXX-api在線上git網站管理,有多個分支版本。現在需要接收別人代碼&#xff0c;導入到本機管理。可以實現本機切換&#xff0c;修改&#xff0c;上傳。2.創建本地倉庫并拉取所有版本2.1.創建目錄在D:\ideaworkspace\midend-…

Android ADB命令之內存統計與分析

一、核心命令總覽工具 / 命令用途示例adb shell dumpsys meminfo查看設備全局內存狀態adb shell dumpsys meminfoadb shell dumpsys meminfo <package>獲取應用詳細內存分類統計adb shell dumpsys meminfo com.example.appadb shell top動態查看進程內存和 CPU 占用adb s…

算法思維進階 力扣 300.最長遞增子序列 暴力搜索 記憶化搜索 DFS 動態規劃 C++詳細算法解析 每日一題

目錄零、題目描述一、為什么這道題值得你深入理解&#xff1f;二、題目拆解&#xff1a;提取核心關鍵點三、明確思路&#xff1a;從暴力到優化的完整進化3. 進一步優化&#xff1a;動態規劃&#xff08;自底向上遞推&#xff09;4. 終極優化&#xff1a;貪心 二分查找&#xf…

圖解網絡-小林coding筆記(持續更新)

大綱 #mermaid-svg-trl6Q4B1uDO1z05w {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-trl6Q4B1uDO1z05w .error-icon{fill:#552222;}#mermaid-svg-trl6Q4B1uDO1z05w .error-text{fill:#552222;stroke:#552222;}#merm…

安寶特案例丨AR+AI+SOP?3大技術融合革新軍工航天領域

軍工、航空、航天領域存在 “小批量、多品種、依賴人工經驗裝配”的特性&#xff0c;這長期制約著生產效率與產品質量的提升。 技術融合應用案例 1 Arbigtec 裝配效率提升類&#xff1a; 某型導彈制導系統裝配&#xff1a;采用 AR 眼鏡與 AI 視覺引導系統&#xff0c;200 精…

ip link show 查看/配置網絡接口

ip link show&#xff08;或簡寫為 ip link&#xff09;是 Linux 系統中用于查看和配置網絡接口&#xff08;網卡、虛擬接口等&#xff09;的命令&#xff0c;屬于 iproute2 工具集的一部分。它是現代 Linux 系統中替代傳統 ifconfig 命令的更強大工具。命令詳解 基本語法 ip l…

電科金倉新一代數據庫一體機:以 “云數據庫 - AI 版” 引領 AI 時代數據庫變革

前言 AI時代的數據庫一體機市場&#xff0c;只能用兩個詞來形容&#xff1a;高手云集&#xff0c;戰況激烈&#xff01; 國際巨頭仍在高端市場占據主導地位&#xff0c;但在國產替代的沖擊下&#xff0c;也開始另尋突破口&#xff1b;國內科技大廠攻勢迅猛&#xff0c;通過開源…

IT運維的365天--033 跨交換機部署沒有單獨供電口的愛快AP到另一個地方去

前情提要&#xff1a;由于工作需要&#xff0c;領導要求在車間也添加一個無線網絡供員工和設備使用&#xff0c;之前公司已經有一個愛快網絡供員工使用&#xff0c;且物理隔絕部署在集團辦公樓這邊了。我一向是不喜歡碰到一個小事就拉一條網線&#xff0c;那樣不得搞的跟蜘蛛網…

Flutter開發實戰之路由與導航

第5章:路由與導航 在移動應用開發中,頁面間的跳轉是最基本也是最重要的功能之一。就像我們在現實生活中需要從一個房間走到另一個房間一樣,在App中,用戶需要在不同的界面間自由切換。Flutter提供了強大而靈活的路由系統來管理這些頁面跳轉,本章將深入探討Flutter的路由與…

Android 圖像編輯實戰指南:從基礎操作到進階效果

在移動應用中&#xff0c;圖像編輯功能已成為標配 —— 社交 APP 需要裁剪頭像&#xff0c;電商 APP 需要給商品圖加水印&#xff0c;工具 APP 需要提供濾鏡效果。看似簡單的 “裁剪”“縮放” 背后&#xff0c;實則涉及 Bitmap 像素操作、內存管理、性能優化等核心技術。很多開…

Java從入門到精通!第十八天(JDK17安裝以及網絡編程) 完結篇!!!

三、網絡編程1&#xff0e;網絡編程概述Java 是 Internet 上的語言&#xff0c;它從語言級上提供了對網絡應用程序的支持&#xff0c;程序員能夠很容易開發常見的網絡應用程序。2&#xff0e;網絡的基礎&#xff08;1&#xff09;計算機網絡把分布在不同地理區域的計算機與專門…

C++ STL常用容器總結(vector, deque, list, map, set)

C STL常用容器總結&#xff08;vector, deque, list, map, set&#xff09;1. vector&#xff08;動態數組&#xff09;特點定義和初始化常用操作遍歷方法2. deque&#xff08;雙端隊列&#xff09;特點定義和初始化常用操作3. list&#xff08;雙向鏈表&#xff09;特點定義和…

智能小車(F103C8T6)RT-THREAD版

前言 前面幾章學會了PWM,超聲波等&#xff0c;現在剛好結合起來控制智能小車 1&#xff1a;環境 KEIL5.38 RT-THREAD 3.1.3 STM32F103C8T6 2&#xff1a;硬件配件&#xff08;原來網上買的一套&#xff09; STM32F103C8T6 一個 MCU底板 一個 SG90 舵機 一個 紅外避障 2個 hc-…

Linux 遠程連接與文件傳輸:從基礎到高級配置

Linux 遠程連接與文件傳輸&#xff1a;從基礎到高級配置 在 Linux 系統管理中&#xff0c;遠程連接和文件傳輸是核心技能。SSH 協議提供了安全的遠程訪問方式&#xff0c;而基于 SSH 的 SFTP 和 SCP 則解決了跨服務器文件傳輸的需求。下面將詳細解析 SSH 服務配置、三種遠程操作…

17. 如何修改 flex 主軸方向

總結 flex-direction: row | row-reverse | column | column-reverse;一、作用說明 在 Flex 布局中&#xff0c;默認的主軸&#xff08;main axis&#xff09;方向是 水平向右&#xff08;即 row&#xff09;。 通過設置 flex-direction 屬性&#xff0c;可以靈活改變主軸的方向…