設計模式:中介者模式 (Mediator)

8 分鐘
軟體設計設計模式OOP

Mediator 把物件之間的通訊集中起來。各元件不再彼此直接溝通,而是透過中介者轉發訊息,把多對多的耦合,收斂成星型結構。


意圖與用途

想像一個介面上有多個元件:搜尋框、列表、按鈕、狀態列。當搜尋框內容改變時,它應該要篩選列表、啟用某個按鈕,並更新狀態列。

如果每個元件都直接引用其他元件,就會形成一張糾纏的依賴網。Mediator 把這些通訊全收進一個中央協調者。


結構與角色

  • Mediator:定義元件之間通訊的介面
  • ConcreteMediator:實作元件之間的協調邏輯
  • Colleague:透過中介者運作的各個元件

實作範例:聊天室中介者

TypeScript
interface ChatMediator {
  sendMessage(message: string, sender: User): void;
  addUser(user: User): void;
}

// Colleague
class User {
  constructor(
    public name: string,
    private mediator: ChatMediator,
  ) {}

  send(message: string): void {
    console.log(`${this.name} 發送:${message}`);
    this.mediator.sendMessage(message, this);
  }

  receive(message: string, from: User): void {
    console.log(`${this.name} 收到來自 ${from.name} 的訊息:${message}`);
  }
}

// ConcreteMediator:公開聊天室
class PublicChatRoom implements ChatMediator {
  private users: User[] = [];

  addUser(user: User): void {
    this.users.push(user);
  }

  sendMessage(message: string, sender: User): void {
    this.users
      .filter(user => user !== sender)
      .forEach(user => user.receive(message, sender));
  }
}

// ConcreteMediator:私訊頻道
class DirectMessageRoom implements ChatMediator {
  private users: User[] = [];
  private messageHistory: string[] = [];

  addUser(user: User): void {
    if (this.users.length >= 2) {
      throw new Error('私訊頻道只支援兩個使用者');
    }
    this.users.push(user);
  }

  sendMessage(message: string, sender: User): void {
    this.messageHistory.push(`[${sender.name}] ${message}`);
    const recipient = this.users.find(u => u !== sender);
    recipient?.receive(message, sender);
  }

  getHistory(): string[] {
    return [...this.messageHistory];
  }
}

// 使用
const publicRoom = new PublicChatRoom();
const alice = new User('Alice', publicRoom);
const bob = new User('Bob', publicRoom);
const charlie = new User('Charlie', publicRoom);

publicRoom.addUser(alice);
publicRoom.addUser(bob);
publicRoom.addUser(charlie);

alice.send('大家好!');
// Bob 收到來自 Alice 的訊息:大家好!
// Charlie 收到來自 Alice 的訊息:大家好!

適用情境

適用時機

  • 多個元件彼此直接引用,形成一張高耦合的網
  • 需要一個集中的地方來管理元件之間複雜的互動邏輯

Mediator vs. Observer

MediatorObserver
通訊方式集中到中介者Subject 廣播給所有 Observer
耦合程度低 (元件只認識中介者)低 (Observer 彼此互不知情)
典型應用介面對話框管理事件/狀態通知

總結

Mediator 把多對多的耦合,轉成一個星型結構:所有元件都只認識中介者。中介者於是成為整場對話的樞紐,封裝了所有協調邏輯。

在實務上,表單管理器、訊息中心,以及元件庫的事件中樞,骨子裡都是 Mediator。