百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python设计模式 第 13 章 中介者模式(Mediator Pattern)

off999 2025-09-06 10:20 70 浏览 0 评论

在行为型模式中,中介者模式是解决 “多对象间网状耦合” 问题的核心模式。它就像 “机场调度中心”—— 多个航班(对象)无需直接沟通起飞、降落时间,只需通过调度中心(中介者)协调,避免航班间的冲突与混乱。在软件开发中,当系统包含多个相互依赖、频繁交互的对象(如 UI 组件、服务模块),且对象间直接耦合导致代码难以维护时,中介者模式可通过 “中介者对象” 统一管理对象间的交互逻辑,将 “网状耦合” 转化为 “星型结构”,降低系统复杂度。本章将从中介者模式的核心概念出发,详细讲解其实现原理、Python 代码实现、实际应用场景及与其他模式的差异。

13.1 中介者模式的定义与核心问题

13.1.1 定义

中介者模式(Mediator Pattern)的官方定义为:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互

简单来说,中介者模式就像 “房屋中介”—— 房东(对象 A)和租客(对象 B)无需直接沟通房屋租赁细节(价格、看房时间、合同签订),只需通过中介(中介者)传递信息,中介负责协调双方需求,避免直接耦合。例如,电商购物车系统中,“商品选择”“库存检查”“价格计算”“优惠券抵扣” 四个模块需频繁交互(选择商品后需检查库存、更新价格、计算优惠),通过中介者模式,各模块只需向中介者发送事件,由中介者统一协调其他模块响应,无需模块间直接调用。

13.1.2 核心问题:多对象交互的网状耦合困境

在未使用中介者模式时,多个对象直接交互会形成 “网状耦合” 结构,面临以下问题:

  1. 耦合度极高:每个对象需持有其他多个对象的引用(如商品模块需引用库存、价格、优惠券模块),若某一对象修改(如库存模块接口变更),所有依赖它的对象都需同步修改;
  1. 代码维护困难:对象间的交互逻辑分散在各个对象中(如商品选择后,商品模块需调用库存检查、价格计算),问题排查时需追踪多个对象的调用链路,定位难度大;
  1. 扩展性差:新增对象时(如新增 “运费计算” 模块),需修改所有相关对象的代码,使其引用新模块(如商品模块需调用运费计算),违背开闭原则;
  1. 复用性低:对象因强依赖其他对象,难以单独复用(如将库存模块复用至其他系统,需同时迁移商品、价格等依赖模块);
  1. 交互逻辑混乱:多个对象同时交互时(如商品选择、优惠券使用、库存不足同时发生),容易出现逻辑冲突(如优惠券已抵扣但库存不足,需回滚优惠),难以协调。

中介者模式通过 “中介者对象” 解决上述问题:所有对象将交互逻辑委托给中介者,对象间仅通过中介者传递信息(如发送事件、请求数据),无需直接引用,将 “网状耦合” 转化为 “对象 - 中介者 - 对象” 的星型结构,实现 “解耦、集中管理、灵活扩展” 的交互逻辑。

13.1.3 生活中的中介者模式案例

  • 机场调度中心:航班(对象)→ 调度中心(中介者)→ 其他航班 / 塔台(对象),调度中心协调航班起飞、降落时间,避免冲突;
  • 房屋中介:房东(对象 A)/ 租客(对象 B)→ 中介(中介者),中介传递需求、协调看房、签订合同;
  • 聊天室:用户(对象)→ 聊天室服务器(中介者)→ 其他用户(对象),用户发送消息至服务器,服务器转发给其他用户,无需用户间直接连接;
  • 交通指挥中心:车辆(对象)→ 指挥中心(中介者)→ 红绿灯 / 其他车辆(对象),指挥中心统一调度交通,避免拥堵。

13.2 中介者模式的核心角色

中介者模式包含 4 个核心角色,通过 “中介者统一协调” 实现对象间的解耦,各角色职责明确且协作紧密:

角色名称

核心职责

实现方式(Python)

抽象中介者(Mediator)

定义中介者与同事对象的交互接口,包含 “注册同事对象”(register_colleague())和 “处理同事对象事件”(handle_event())的抽象方法,规范中介者行为

抽象基类(abc.ABC),定义抽象方法,可包含同事对象的集合属性

具体中介者(Concrete Mediator)

实现抽象中介者的接口,维护所有同事对象的引用,实现具体的交互协调逻辑(如 “商品选择事件” 触发库存检查、价格计算),是中介者模式的核心

继承抽象中介者类,在__init__中初始化同事对象集合,重写handle_event()方法,根据事件类型协调其他同事对象

抽象同事类(Colleague)

定义同事对象的公共接口,包含 “关联中介者”(set_mediator())和 “发送事件”(send_event())的抽象方法,规范同事对象与中介者的交互

抽象基类(abc.ABC),定义抽象方法,持有抽象中介者的引用(mediator属性)

具体同事类(Concrete Colleague)

实现抽象同事类的接口,包含自身的业务逻辑(如商品选择、库存检查),当自身状态变化时,通过send_event()向中介者发送事件,无需直接与其他同事对象交互

继承抽象同事类,重写send_event()方法(调用中介者的handle_event()),实现自身的业务方法(如select_product()“check_stock())

角色间的协作流程

  1. 客户端创建 “具体中介者” 对象;
  1. 客户端创建多个 “具体同事类” 对象,调用set_mediator()方法关联中介者;
  1. 客户端将同事对象注册到中介者(中介者维护同事对象集合,便于后续调用);
  1. 某一同事对象状态变化(如用户选择商品),调用send_event()向中介者发送事件(如 “商品选择事件”,携带商品 ID、数量);
  1. 中介者的handle_event()方法接收事件,根据事件类型和参数,调用其他同事对象的业务方法(如调用库存模块检查库存、价格模块计算总价);
  1. 其他同事对象执行业务逻辑后,若需进一步交互,可通过send_event()向中介者发送新事件(如库存不足,发送 “库存不足事件”);
  1. 中介者继续协调其他对象响应新事件(如库存不足时,调用 UI 模块显示提示信息),直至交互结束。

13.3 中介者模式的 Python 实现(基础版)

以 “电商购物车” 为例,实现包含 “商品选择”“库存检查”“价格计算”“优惠券抵扣” 4 个同事模块的中介者,各模块通过中介者协调交互,避免直接耦合。

13.3.1 步骤 1:定义抽象中介者(Mediator)

创建抽象中介者类,定义 “注册同事对象” 和 “处理事件” 的抽象方法,规范中介者与同事对象的交互接口。

from abc import ABC, abstractmethod

from typing import Dict, Any, Optional

# 抽象中介者:购物车中介者(CartMediator)

class CartMediator(ABC):

def __init__(self):

self.colleagues: Dict[str, "CartColleague"] = {} # 存储同事对象(key:模块名,value:同事对象)

@abstractmethod

def register_colleague(self, colleague: "CartColleague") -> None:

"""抽象方法:注册同事对象到中介者"""

pass

@abstractmethod

def handle_event(self, colleague_name: str, event_type: str, data: Optional[Dict] = None) -> Any:

"""

抽象方法:处理同事对象发送的事件

:param colleague_name: 发送事件的同事对象名称

:param event_type: 事件类型(如"select_product"“check_stock”)

:param data: 事件数据(如商品ID、数量)

:return: 事件处理结果(可选)

"""

pass

13.3.2 步骤 2:定义抽象同事类(Colleague)

创建抽象同事类,定义 “关联中介者” 和 “发送事件” 的抽象方法,规范同事对象与中介者的交互方式。

# 抽象同事类:购物车同事模块(CartColleague)

class CartColleague(ABC):

def __init__(self, name: str):

self.name = name # 同事对象名称(如"product"“stock”“price”“coupon”)

self.mediator: Optional[CartMediator] = None # 关联的中介者

@abstractmethod

def set_mediator(self, mediator: CartMediator) -> None:

"""抽象方法:关联中介者"""

pass

@abstractmethod

def send_event(self, event_type: str, data: Optional[Dict] = None) -> Any:

"""抽象方法:向中介者发送事件"""

pass

@abstractmethod

def handle_event(self, event_type: str, data: Optional[Dict] = None) -> Any:

"""抽象方法:处理中介者转发的事件(如其他模块触发的事件)"""

pass

13.3.3 步骤 3:实现具体同事类(Concrete Colleague)

分别实现 “商品选择”“库存检查”“价格计算”“优惠券抵扣” 4 个同事模块,每个模块实现自身的业务逻辑,状态变化时通过中介者发送事件。

同事类 1:商品选择模块(ProductColleague)

# 具体同事类1:商品选择模块(ProductColleague)

class ProductColleague(CartColleague):

def __init__(self):

super().__init__(name="product")

self.selected_products: Dict[str, int] = {} # 已选商品(key:商品ID,value:数量)

def set_mediator(self, mediator: CartMediator) -> None:

"""关联中介者"""

self.mediator = mediator

def send_event(self, event_type: str, data: Optional[Dict] = None) -> Any:

"""向中介者发送事件(如“选择商品”“取消选择”)"""

if self.mediator:

return self.mediator.handle_event(self.name, event_type, data)

else:

raise ValueError("未关联中介者,无法发送事件")

def handle_event(self, event_type: str, data: Optional[Dict] = None) -> Any:

"""处理中介者转发的事件(如其他模块请求获取已选商品)"""

if event_type == "get_selected_products":

# 价格模块或优惠券模块请求已选商品

print(f"[{self.name}] 处理事件:{event_type},返回已选商品:{self.selected_products}")

return self.selected_products

else:

print(f"[{self.name}] 不支持的事件类型:{event_type}")

return None

def select_product(self, product_id: str, quantity: int) -> None:

"""选择商品(自身业务逻辑),发送“商品选择”事件给中介者"""

if quantity <= 0:

print(f"[{self.name}] 商品{product_id}选择数量无效:{quantity}")

return

# 更新已选商品

self.selected_products[product_id] = self.selected_products.get(product_id, 0) + quantity

print(f"[{self.name}] 已选择商品:{product_id},数量:{self.selected_products[product_id]}")

# 向中介者发送“商品选择”事件,触发其他模块响应

self.send_event(

event_type="select_product",

data={"product_id": product_id, "quantity": quantity}

)

def unselect_product(self, product_id: str) -> None:

"""取消选择商品,发送“取消选择”事件给中介者"""

if product_id in self.selected_products:

del self.selected_products[product_id]

print(f"[{self.name}] 已取消选择商品:{product_id}")

# 向中介者发送“取消选择”事件

self.send_event(

event_type="unselect_product",

data={"product_id": product_id}

)

else:

print(f"[{self.name}] 未选择商品:{product_id},无法取消")

同事类 2:库存检查模块(StockColleague)

# 具体同事类2:库存检查模块(StockColleague)

class StockColleague(CartColleague):

def __init__(self):

super().__init__(name="stock")

# 模拟库存数据(key:商品ID,value:可用库存)

self.stock_data: Dict[str, int] = {

"prod_001": 100, # 商品1库存100

"prod_002": 5, # 商品2库存5

"prod_003": 0 # 商品3库存0

}

def set_mediator(self, mediator: CartMediator) -> None:

self.mediator = mediator

def send_event(self, event_type: str, data: Optional[Dict] = None) -> Any:

if self.mediator:

return self.mediator.handle_event(self.name, event_type, data)

else:

raise ValueError("未关联中介者,无法发送事件")

def handle_event(self, event_type: str, data: Optional[Dict] = None) -> Any:

"""处理事件:检查库存、扣减库存"""

if event_type == "check_stock" and data:

product_id = data.get("product_id")

quantity = data.get("quantity", 0)

if not product_id:

return {"success": False, "message": "商品ID不能为空"}

# 检查库存

available_stock = self.stock_data.get(product_id, 0)

if available_stock >= quantity:

result = {"success": True, "available_stock": available_stock, "message": "库存充足"}

else:

result = {"success": False, "available_stock": available_stock, "message": "库存不足"}

print(f"[{self.name}] 处理事件:{event_type},商品{product_id},需求{quantity},结果:{result['message']}")

return result

elif event_type == "deduct_stock" and data:

# 扣减库存(仅下单时触发)

product_id = data.get("product_id")

quantity = data.get("quantity", 0)

if product_id in self.stock_data and self.stock_data[product_id] >= quantity:

self.stock_data[product_id] -= quantity

print(f"[{self.name}] 处理事件:{event_type},商品{product_id},扣减{quantity},剩余库存:{self.stock_data[product_id]}")

return {"success": True, "message": "库存扣减成功"}

else:

print(f"[{self.name}] 处理事件:{event_type},商品{product_id}库存不足,无法扣减")

return {"success": False, "message": "库存不足"}

else:

print(f"[{self.name}] 不支持的事件类型:{event_type}")

return None

同事类 3:价格计算模块(PriceColleague)

# 具体同事类3:价格计算模块(PriceColleague)

class PriceColleague(CartColleague):

def __init__(self):

super().__init__(name="price")

# 商品单价(key:商品ID,value:单价(元))

self.product_prices: Dict[str, float] = {

"prod_001": 99.9,

"prod_002": 199.8,

"prod_003": 299.7

}

self.total_price: float = 0.0 # 总价(未抵扣优惠券)

def set_mediator(self, mediator: CartMediator) -> None:

self.mediator = mediator

def send_event(self, event_type: str, data: Optional[Dict] = None) -> Any:

if self.mediator:

return self.mediator.handle_event(self.name, event_type, data)

else:

raise ValueError("未关联中介者,无法发送事件")

</doubaocanvas>

相关推荐

电脑蓝屏重新启动(电脑蓝屏重新启动快捷键)
  • 电脑蓝屏重新启动(电脑蓝屏重新启动快捷键)
  • 电脑蓝屏重新启动(电脑蓝屏重新启动快捷键)
  • 电脑蓝屏重新启动(电脑蓝屏重新启动快捷键)
  • 电脑蓝屏重新启动(电脑蓝屏重新启动快捷键)
恢复大师app下载(恢复大师app下载软件)

是真的。开心手机恢复大师是一款苹果手机数据恢复软件,可以恢复删除的微信聊天记录、短信、通讯录、备忘录、qq聊天记录等17种数据。我测试了一下,确实是可以恢复的。而且开心手机恢复大师是可以免费试用的,是...

windowsxp下载网站(windows xp download)

目前无法下载因为红色警戒XP电脑版是一款已经停止开发的游戏,官方已经停止了对其的支持和更新。虽然网上有一些模拟器可以运行该游戏,但是安装和使用相对困难,而且可能存在版权问题。建议玩家选择其他同类型的游...

没人用过的激活码没过期(没人用过的激活码没过期可以用吗)

迷你世界并不存在什么激活码的。《迷你世界》是一款高度自由的休闲类3D沙盒游戏,有着非常方便快捷的多人联机模式,只要有网络就能和各个地方的小伙伴们一起玩。这里没有等级和规则限制,没有规定的玩法,只有随心...

2017年联想笔记本电脑有几款

17年的笔记本电脑可以勉强安装一下win10系统试试。关键看你的内存有多少,内存大于4个G的话可以安装win10速度不会太慢。最好是安装win7系统,这样能发挥你这台电脑的所有的性能,你用起来也会感觉...

当前显卡排名(当下显卡排行)

101、Irispro5802、Iris62002、Iris52004、UHD630/6205、HD6306、HD5307、HD46008、HD44009、HD420010、HD40...

win10专业版激活变成企业版(win10专业版激活变成企业版怎么办)

win10永久激活密钥很少,一旦网上有分享,等你拿到时就超过期限了,一般是要购买。激活win10系统可以使用激活工具:win10激活工具下载一、win10专业版产品密钥NXRQM-CXV6P-PBGV...

ghostwinxp下载纯净版(ghost win7纯净版下载)

可以下载的,现在官网和其他网站上都可以下载xp原版的。可以通过以下步骤下载我的世界游戏到xp系统中:1.首先打开你的浏览器软件,搜索关键字“我的世界xp版下载”,找到可靠下载地址;2.从下载页面下...

惠普完整版驱动(惠普最新驱动)

惠普官方的标准操作:HP1050安装驱动步骤:一:准备:拿出驱动光盘放入光驱或到HP官网下载完整版驱动。二:不要插USB数据线或插上线打印机电源不要开,安装完整版驱动,当程序提示插入USB数据线时,插...

浏览器最好用的(浏览器最好用的插件)

一、谷歌浏览器谷歌浏览器是公认最好用的,这个可以从市场占有率看出端倪,超过三分之二的用户使用谷歌浏览器。Chrome浏览器以简洁快速著称,不管是普通用户还是开发人员,chrome浏览器都是首选。Chr...

fast路由器6位初始密码(fast路由器的密码)

答:fast路由器初始密码是admin;新款的迅捷无线路由器,管理界面没有初始密码。查看迅捷无线路由器底部标签,标签上标注了admin,说明初始密码就是admin;如果没有,说明该路由器没有初始密码。...

硬盘恢复软件哪个好(硬盘 恢复软件)

迷你兔数据恢复工具:支持恢复硬盘丢失的数据Pc3000数据恢复软件是一款非常专业的硬盘修复工具,能够对电脑硬盘资料数据进行修复,通过使用这个软件可以解决硬盘数据丢失故障,是一个用户进行硬盘资料修复好帮...

十大品牌监控摄像头排名(十大品牌监控摄像头排名第一)

答:1、华为/HUAWEI9.92、小米/MI9.63、罗技/Logitech9.64、海康威视/HIKVISION9.25、乔安/Jooan9.26、普联/TP-LINK9.27、乐橙8.98、萤石...

360手机助手老旧版本大全(360手机助手 老版本)

在设置里面找到历史记录就可能查看360手机助手·换机神器是安卓系统的换机软件,因为苹果的换机软件是爱思。1、打开360手机卫士,登陆账号,点击账号。2、进入个人中心,点击账户安全,在密保工具中,点击解...

系统应用工程师(系统工程的应用)

信息软件系统工程师有前途,毕业以后可以从事软件开发,软件系统的维护,运营等等,和计算机有关的工作内容,因为计算机专业可以说是一个非常热门的专业,很多的大型企业公司基本上都是以计算机研发为主的,薪资福利...

取消回复欢迎 发表评论: