對于那些存在物件之間復雜互動關系的系統,中介者模式提供了一種簡化復雜互動的解決方案,即通過引入一個中介者,將原本物件之間的兩兩互動轉化為每個物件與中介者之間的互動
模式動機
以微信聊天為例,可以用戶與用戶直接聊天,也可以通過微信群聊天,前者的話,用戶要和別的用戶加為好友,即用戶和用戶之間存在多對多關系,一個用戶如果要將相同的資訊發送給所有其他用戶,必須一個一個發送,而如果使用群聊天,一個用戶可以向多個用戶發送相同資訊而無須一一進行發送,只需將資訊發送到群中即可,群的作用就是將發送者所發送的資訊轉發給每一個接收者用戶,
在用戶與用戶直接聊天的設計方案中,用戶物件之間存在很強關聯性,將導致系統出現如下問題:
- 系統結構復雜
- 物件可重用性差
- 系統擴展混亂
根據單一職責原則,我們應盡量將物件細化,使其只負責單一職責,一個由很多物件構成的模塊,為了減少物件兩兩之間復雜的參考關系,我們需要使用中介者模式,這就是中介者模式的模式動機,
模式定義
用一個中介物件來封裝一系列物件互動,中介者使各物件不需顯式地相互參考,從而使其耦合松散,而且可以獨立改變它們之間的互動,中介者模式又稱調停者模式,它是一種物件行為型模式,
模式結構

-
Mediator(抽象中介者)
定義一個介面,該介面應用于各同事物件之間的通信
-
ConcreteMediator(具體中介者)
抽象中介類的子類,通過協調各個同事物件來實作協作行為,了解并維護它對各個同事物件的參考,
-
Colleague(抽象同事類)
定義各同事的公有方法
-
ConcreteColleague(具體同事類)
每一個同事物件都參考一個中介者物件,每一個同事物件在需要時和其他同事物件通信時,先與中介者通信,通過中介者來間接完成與其他同事的通信
模式分析
通過引入中介者物件,可以將系統的網狀結構變成以中介者為中心的星狀結構,在這個形狀結構中,同事物件不再直接與另一個物件聯系,它通過中介者物件與另一個物件發生相互作用,

如果物件之間存在多對多的相互關系,可以將物件之間的一些互動行為從各個物件中分離出來,并集中封裝在一個中介者物件中,并由該中介者進行通信和協調,這樣物件間的多對多的復雜關系就可以通過簡單的多對一關系實作,符合迪米特法則,即“只與你直接的朋友們通信,而且只要可能,朋友數目越少越好”,
中介者承擔了以下兩方面的職責:
- 中轉作用:通過中介者提供的中轉作用,各個同事物件不需要顯式參考其他同事,當需要和其他同事進行通信時,通過中介者即可
- 協調作用:中介者可以更進一步對同事之間的關系進行封裝,同事一致地和中介者進行互動,而不需要指明中介者具體怎么做,中介者根據封裝在自身內部的邏輯協調,對同事的請求進行進一步處理,將同事成員之間的關系行為進行分離和封裝
模式實體之虛擬聊天室
某論壇會員通過聊天室進行資訊交流,普通會員(CommonMember)可以給其他會員發送文本資訊,鉆石會員(DiamondMember)既可以給其他會員發送文本資訊,還可以發送圖片資訊,聊天室可以對不雅字符進行過濾,可以對發送圖片的大小進行控制,

-
抽象中介者類 AbstractChatroom(抽象聊天室類)
public abstract class AbstractChatroom { // 注冊同事物件的方法 public abstract void register(Member member); // 同事之間發送文本資訊方法 public abstract void sendText(String from, String to, String message); // 同事之間發送圖片資訊 public abstract void sendImage(String from, String to, String image); } -
抽象同事類 Member(抽象會員類)
public abstract class Member { // 維持一個抽象中介者的參考,用于呼叫中介者的方法 protected AbstractChatroom chatroom; protected String name; public Member(String name) { this.name = name; } public AbstractChatroom getChatroom() { return chatroom; } public void setChatroom(AbstractChatroom chatroom) { this.chatroom = chatroom; } public String getName() { return name; } public void setName(String name) { this.name = name; } // 由于不同型別會員發送文本資訊和圖片資訊的方式不同 // 因此對這兩個方法進行抽象宣告 public abstract void sendText(String to, String message); public abstract void sendImage(String to, String image); public void receiveText(String from, String message) { System.out.println(from + "發送文本給" + this.name + ",內容為:" + message); } public void receiveImage(String from, String image) { System.out.println(from + "發送圖片給" + this.name + ",內容為:" + image); } } -
具體中介者類 ChatGroup(具體聊天室類)
import java.util.Hashtable; public class ChatGroup extends AbstractChatroom { // 定義一個集合物件存盤需要發生互動的同事物件 private Hashtable<String, Member> members = new Hashtable<String, Member>(); // 提供注冊方式,將同事物件加入集合中 @Override public void register(Member member) { if (!members.contains(member)) { members.put(member.getName(), member); member.setChatroom(this); } } @Override public void sendText(String from, String to, String message) { Member member = members.get(to); String newMessage = message; // 模擬不雅字符過濾 newMessage = message.replace("日", "*"); // 呼叫會員接收方法 member.receiveText(from, newMessage); } @Override public void sendImage(String from, String to, String image) { Member member = members.get(to); // 模擬圖片大小判斷 if (image.length() > 5) { System.out.println("圖片太大,發送失敗"); } else { // 呼叫會員接收方法 member.receiveImage(from, image); } } } -
具體同事類 CommonMember(普通會員類)
public class CommonMember extends Member { public CommonMember(String name) { super(name); } @Override public void sendText(String to, String message) { System.out.println("普通會員發送資訊:"); chatroom.sendText(name, to, message); } @Override public void sendImage(String to, String image) { System.out.println("普通會員不能發送圖片!"); } } -
具體同事類 DiamondMember(鉆石會員類)
public class DiamondMember extends Member { public DiamondMember(String name) { super(name); } @Override public void sendText(String to, String message) { System.out.println("鉆石會員發送資訊:"); chatroom.sendText(name, to, message); } @Override public void sendImage(String to, String image) { System.out.println("鉆石會員發送圖片"); chatroom.sendImage(name, to, image); } } -
客戶端測驗類 Client
public class Client { public static void main(String[] args) { AbstractChatroom happyChat = new ChatGroup(); Member member1, member2, member3, member4, member5; member1 = new DiamondMember("張三"); member2 = new DiamondMember("李四"); member3 = new CommonMember("王五"); member4 = new CommonMember("小芳"); member5 = new CommonMember("小紅"); happyChat.register(member1); happyChat.register(member2); happyChat.register(member3); happyChat.register(member4); happyChat.register(member5); member1.sendText("李四", "李四,你好"); member2.sendText("張三", "張三,你好"); member1.sendText("李四", "今天天氣不錯,有日"); member2.sendImage("張三", "一個很大很大的太陽"); member2.sendImage("張三", "太陽"); member3.sendText("小芳", "還有問題嗎?"); member3.sendText("小紅", "還有問題嗎?"); member4.sendText("王五", "沒有了,謝謝"); member5.sendText("王五", "我也沒有了"); member5.sendImage("王五", "謝謝"); } } -
運行結果

如果需要增加新的具體中介類,只需繼承抽象中介者類并實作其中方法即可,新的具體中介者類可以對資訊進行不同的處理,客戶端只需修改少量代碼(如果使用組態檔的話可以不修改代碼)
如果增加新的同事類,繼承抽象同事類并實作即可,同事類之間無直接參考關系,本實體中,中介者對同事類的參考建立在抽象層,因此在客戶端實體化新增的同事類即可直接使用該物件
模式優缺點
中介者模式優點:
- 簡化物件間的互動,用中介者和同事的一對多互動代替了原來同事之間多對多互動,更利于理解、維護和擴展,
- 將各同事解耦,我們可以獨立的改變、增加和復用各同事和中介者,符合開閉原則
- 減少子類生成,中介者將原本分布于多個物件的行為集合在一起,改變這些行為只需生成新的中介者子類即可,各個同事類可被重用,
中介者模式缺點:
- 具體中介者類包含了同事之間的互動細節,可能會導致中介者類非常復雜,難以維護,
模式適用環境
以下情況可以使用中介者模式:
- 系統物件之間存在復雜的參考關系
- 一個物件由于參考了其他很多物件并直接與其通信,導致難以復用該物件
- 想通過一個中間類來封裝多個類的行為,而又不想生成太多子類,可以使用中介者類,在中介者類中定義物件互動的公共行為
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/8594.html
標籤:設計模式
上一篇:設計模式之工廠模式
