Python 中的中介者模式(Mediator Pattern)

中介者模式是一种行为型设计模式,其核心目的是:
用一个中介者对象来封装一系列对象之间的交互。中介者使各对象不需要显式地相互引用,从而降低它们之间的耦合度,而且可以独立地改变它们的交互行为。

形象比喻:就像机场的控制塔——每架飞机不需要直接和其他飞机通信,只需和控制塔(中介者)联系,由控制塔协调起飞、降落、航线,避免飞机之间直接“聊天”导致混乱。

中介者模式的优点
  • 降低耦合:对象之间不再直接持有引用(松耦合)
  • 集中控制交互逻辑:复杂通信规则集中在中介者中,便于维护
  • 简化对象协议:每个对象只关注自身行为和与中介者的通信
  • 易于扩展:新增同事对象只需注册到中介者
  • 支持广播和一对一通信
典型应用场景
  • 聊天室(所有用户通过服务器发送消息)
  • GUI 组件交互(按钮、文本框、下拉框之间的联动)
  • 工作流系统(各部门通过流程引擎协调)
  • 游戏中单位间通信(玩家、NPC、怪物通过游戏管理器交互)
  • 微服务事件总线
Python 实现示例:聊天室系统
from abc import ABC, abstractmethod
from typing import List

# 中介者接口(Mediator)
class ChatRoom(ABC):
    @abstractmethod
    def send_message(self, sender: 'User', message: str):
        pass

    @abstractmethod
    def register(self, user: 'User'):
        pass

# 具体中介者:聊天室
class ConcreteChatRoom(ChatRoom):
    def __init__(self):
        self.users: List['User'] = []

    def register(self, user: 'User'):
        if user not in self.users:
            self.users.append(user)
            user.chat_room = self
            print(f"{user.name} 加入聊天室")

    def send_message(self, sender: 'User', message: str):
        # 中介者负责广播(排除发送者自己)
        print(f"[{sender.name}]: {message}")
        for user in self.users:
            if user != sender:  # 不发给自己
                user.receive(message)

# 同事类(Colleague)
class User:
    def __init__(self, name: str):
        self.name = name
        self.chat_room: ChatRoom = None  # 持有中介者引用

    def send(self, message: str):
        if self.chat_room is None:
            print(f"{self.name} 尚未加入任何聊天室")
            return
        print(f"{self.name} 发送消息...")
        self.chat_room.send_message(self, message)

    def receive(self, message: str):
        print(f"  → {self.name} 收到: {message}")

# 客户端使用
if __name__ == "__main__":
    # 创建中介者
    chat_room = ConcreteChatRoom()

    # 创建用户(同事)
    alice = User("Alice")
    bob = User("Bob")
    charlie = User("Charlie")

    # 用户注册到中介者
    chat_room.register(alice)
    chat_room.register(bob)
    chat_room.register(charlie)

    print("\n--- 开始聊天 ---")
    alice.send("大家好!")
    bob.send("Hi Alice!")
    charlie.send("今天天气真好~")
    alice.send("确实!要去散步吗?")

输出

Alice 加入聊天室
Bob 加入聊天室
Charlie 加入聊天室

--- 开始聊天 ---
Alice 发送消息...
[Alice]: 大家好!
  → Bob 收到: 大家好!
  → Charlie 收到: 大家好!
Bob 发送消息...
[Bob]: Hi Alice!
  → Alice 收到: Hi Alice!
  → Charlie 收到: Hi Alice!
Charlie 发送消息...
[Charlie]: 今天天气真好~
  → Alice 收到: 今天天气真好~
  → Bob 收到: 今天天气真好~
Alice 发送消息...
[Alice]: 确实!要去散步吗?
  → Bob 收到: 确实!要去散步吗?
  → Charlie 收到: 确实!要去散步吗?

用户之间没有直接引用,所有通信都通过 ChatRoom 中介者完成。

更实用的例子:GUI 组件中介者

假设有一个表单:字体选择框、粗体复选框、斜体复选框、预览文本框。当用户改变任意一个选项,其他组件应同步更新。

class DialogMediator:
    def __init__(self):
        self.font_selector = None
        self.bold_checkbox = None
        self.italic_checkbox = None
        self.preview_label = None

    def register_components(self, font_selector, bold_checkbox, italic_checkbox, preview_label):
        self.font_selector = font_selector
        self.bold_checkbox = bold_checkbox
        self.italic_checkbox = italic_checkbox
        self.preview_label = preview_label

    def notify(self, sender, event):
        if sender == self.font_selector:
            self.update_preview()
        elif sender == self.bold_checkbox:
            self.update_preview()
        elif sender == self.italic_checkbox:
            self.update_preview()

    def update_preview(self):
        font = self.font_selector.get_value()
        bold = "bold" if self.bold_checkbox.is_checked() else "normal"
        italic = "italic" if self.italic_checkbox.is_checked() else "normal"
        style = f"{bold} {italic} {font}"
        self.preview_label.set_text(f"预览文字 - 样式: {style}")

# 模拟组件类
class FontSelector:
    def __init__(self, mediator: DialogMediator):
        self.mediator = mediator
        self.value = "Arial"

    def get_value(self):
        return self.value

    def change(self, new_font):
        self.value = new_font
        self.mediator.notify(self, "change")

class CheckBox:
    def __init__(self, mediator: DialogMediator, label: str):
        self.mediator = mediator
        self.label = label
        self.checked = False

    def is_checked(self):
        return self.checked

    def toggle(self):
        self.checked = not self.checked
        self.mediator.notify(self, "toggle")

class PreviewLabel:
    def set_text(self, text):
        print(f"[预览更新]: {text}")

# 使用
mediator = DialogMediator()

font_sel = FontSelector(mediator)
bold_cb = CheckBox(mediator, "Bold")
italic_cb = CheckBox(mediator, "Italic")
preview = PreviewLabel()

mediator.register_components(font_sel, bold_cb, italic_cb, preview)

# 模拟用户操作
font_sel.change("Times New Roman")
bold_cb.toggle()
italic_cb.toggle()
bold_cb.toggle()  # 再次切换

输出

[预览更新]: 预览文字 - 样式: normal normal Times New Roman
[预览更新]: 预览文字 - 样式: bold normal Times New Roman
[预览更新]: 预览文字 - 样式: bold italic Times New Roman
[预览更新]: 预览文字 - 样式: normal italic Times New Roman

组件之间无需相互引用,所有联动逻辑集中在中介者中。

中介者模式结构总结
角色 说明
Mediator 抽象中介者(ChatRoom 接口)
ConcreteMediator 具体中介者(ConcreteChatRoom),协调同事
Colleague 同事类(User),持有中介者引用
ConcreteColleague 具体同事(Alice、Bob 等)
中介者模式 vs 观察者模式对比
模式 通信方式 耦合度 典型场景
中介者 所有通信通过中心中介者 同事松耦合 聊天室、GUI 组件联动
观察者 一对多广播 主题与观察者松耦合 事件通知、发布订阅

中介者更适合多对多复杂交互,观察者更适合一对多通知

Python 中的实用建议
  • 小型系统:直接用一个类作为中介者(最简单)
  • 大型系统:结合事件总线(如 blinker 库)实现轻量中介者
  • GUI 框架:PyQt/PySide 的信号槽机制本质就是中介者模式的一种实现
  • 微服务:消息队列(如 RabbitMQ、Kafka)充当分布式中介者
注意事项
  • 中介者不要变成“上帝类”(God Class),承担过多责任
  • 如果交互逻辑简单,优先考虑直接引用或观察者模式
  • 支持动态注册/注销同事(用户上线/下线)

中介者模式是处理对象间复杂交互的强大工具,能显著降低系统耦合,尤其在 GUI、聊天系统、工作流中非常实用。

如果你想看更高级的例子(如带私聊功能的聊天室、使用事件总线的分布式中介者、GUI 表单完整实现),欢迎继续问!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐