设计模式——中介者设计模式(行为型)

article/2025/7/5 17:48:42

摘要

文章详细介绍了中介者设计模式,这是一种行为型设计模式,通过中介者对象封装多个对象间的交互,降低系统耦合度。文中阐述了其核心角色、优缺点、适用场景,并通过类图、时序图、实现方式、实战示例等多方面进行讲解,还探讨了与其他设计模式的组合使用,帮助读者全面理解该模式。

1. 中介者设计模式定义

中介者设计模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介对象来封装多个对象之间的交互,从而使对象之间不再互相引用,降低系统的耦合度,让对象之间的通信通过中介者统一协调。

飞机起降管控系统:多架飞机(同事对象)之间不能自己协调起降,必须通过“塔台”(中介者)统一调度,这样飞机之间不需要知道彼此,只需与塔台通信。

1.1. 📌 核心角色

角色

说明

Mediator

抽象中介者,定义对象之间通信的接口

ConcreteMediator

具体中介者,实现协调各组件之间的交互逻辑

Colleague

同事类,每个与其他对象通信的对象,只与中介者通信

1.2. ✅ 优点

  • 降低对象之间的耦合,避免“网状结构”,变为“星型结构”
  • 交互集中管理,逻辑清晰、易维护
  • 更易于扩展和修改通信规则

1.3. ❌ 缺点

  • 中介者可能变得非常复杂,成为“上帝类”
  • 不适合同事对象数量很少、交互简单的情况

1.4. ✅ 适用场景

  • 多个对象之间存在复杂交互,导致系统结构混乱
  • 希望将对象间的通信行为提取到一个独立类中进行管理
  • 界面组件交互(如按钮、输入框等)、聊天系统、协作系统

2. 中介者设计模式结构

  1. 组件 (Component) 是各种包含业务逻辑的类。 每个组件都有一个指向中介者的引用, 该引用被声明为中介者接口类型。 组件不知道中介者实际所属的类, 因此你可通过将其连接到不同的中介者以使其能在其他程序中复用。
  2. 中介者 (Mediator) 接口声明了与组件交流的方法, 但通常仅包括一个通知方法。 组件可将任意上下文 (包括自己的对象) 作为该方法的参数, 只有这样接收组件和发送者类之间才不会耦合。
  3. 具体中介者 (Concrete Mediator) 封装了多种组件间的关系。 具体中介者通常会保存所有组件的引用并对其进行管理, 甚至有时会对其生命周期进行管理。

2.1. 中介者模式类图

2.2. 中介者模式时序图

3. 中介者设计模式实现方式

中介者设计模式是一种行为型设计模式,通过引入中介对象封装多个对象之间的交互,从而使对象之间不再互相引用,达到松耦合的目的

3.1. 🧱 核心实现结构

3.1.1. 抽象中介者接口(Mediator

定义统一的通信接口,用于同事对象之间的协调。

public interface Mediator {void notify(String event, Colleague sender);
}

3.1.2. 抽象同事类(Colleague

每个同事类都持有中介者的引用,只与中介者通信。

public abstract class Colleague {protected Mediator mediator;public Colleague(Mediator mediator) {this.mediator = mediator;}
}

3.1.3. 具体同事类(ConcreteColleague

具体的业务类,通过调用中介者来进行通信。

public class ConcreteColleagueA extends Colleague {public ConcreteColleagueA(Mediator mediator) {super(mediator);}public void doSomething() {System.out.println("ColleagueA 执行操作,通知中介者");mediator.notify("A完成", this);}public void receive(String msg) {System.out.println("ColleagueA 收到消息:" + msg);}
}
public class ConcreteColleagueB extends Colleague {public ConcreteColleagueB(Mediator mediator) {super(mediator);}public void doSomething() {System.out.println("ColleagueB 执行操作,通知中介者");mediator.notify("B完成", this);}public void receive(String msg) {System.out.println("ColleagueB 收到消息:" + msg);}
}

3.1.4. 具体中介者类(ConcreteMediator

负责协调同事类之间的通信逻辑。

public class ConcreteMediator implements Mediator {private ConcreteColleagueA colleagueA;private ConcreteColleagueB colleagueB;public void setColleagueA(ConcreteColleagueA a) {this.colleagueA = a;}public void setColleagueB(ConcreteColleagueB b) {this.colleagueB = b;}@Overridepublic void notify(String event, Colleague sender) {if (sender == colleagueA) {colleagueB.receive("来自A的通知:" + event);} else if (sender == colleagueB) {colleagueA.receive("来自B的通知:" + event);}}
}

3.2. 🛠 测试用例

public class Main {public static void main(String[] args) {ConcreteMediator mediator = new ConcreteMediator();ConcreteColleagueA a = new ConcreteColleagueA(mediator);ConcreteColleagueB b = new ConcreteColleagueB(mediator);mediator.setColleagueA(a);mediator.setColleagueB(b);a.doSomething();b.doSomething();}
}

3.3. ✅ 输出示例

ColleagueA 执行操作,通知中介者
ColleagueB 收到消息:来自A的通知:A完成
ColleagueB 执行操作,通知中介者
ColleagueA 收到消息:来自B的通知:B完成

3.4. 🧩 中介者示例总结

角色

职责

Mediator

定义中介者接口,协调同事之间的通信

ConcreteMediator

持有所有同事的引用,封装对象间交互逻辑

Colleague

持有中介者引用,通过中介者与其他对象交互,不直接引用其他对象

应用价值

解耦多个对象间复杂的网状关系,转化为中心化的星型结构,便于扩展和维护

4. 中介者设计模式适合场景

4.1. ✅ 中介者设计模式适合场景

场景描述

说明

多个对象间复杂交互

对象之间交互关系复杂且频繁,使用中介者简化对象间直接通信

需要解耦对象之间的依赖

通过中介者集中管理,减少对象之间的耦合,符合单一职责原则

系统中的对象之间通信逻辑经常变化

中介者封装交互逻辑,修改交互规则只需改中介者,不用改对象

多个模块协作实现复杂业务流程

中介者协调不同模块协作,避免各模块直接耦合

需要统一管理和监控对象间通信

中介者作为统一中心,便于增加日志、监控、事务控制等功能

4.2. ❌ 中介者设计模式不适合场景

对象间通信关系简单,耦合不明显

使用中介者会增加不必要的复杂度,直接通信更清晰简单

对象数量非常少

中介者的抽象和管理成本超过了实际收益

性能要求极高,不允许通信中间层增加延迟

中介者引入了额外的转发和协调,可能导致一定的性能损耗

系统逻辑对对象的独立性和自治性要求较高

中介者集中控制会限制对象自治,增加耦合

需要灵活、动态调整对象间通信方式

中介者模式较为静态,频繁调整通信机制可能导致中介者复杂难维护

5. 中介者设计模式实战示例

下面给你一个基于Spring框架,使用注解注入,非构造函数注入的中介者设计模式实战示例,场景是简化版金融风控系统中多个风控模块(比如信用评分模块、额度计算模块)之间的协作。

5.1. 设计思路

  • 中介者接口:定义协调各风控模块交互的方法
  • 具体中介者类:实现接口,注入各风控模块,协调调用
  • 风控模块接口:所有风控模块统一接口
  • 具体风控模块实现类:业务模块实现

5.2. 中介者接口

public interface RiskMediator {void execute(String action);
}

5.3. 风控模块接口

public interface RiskModule {void check();
}

5.4. 具体风控模块实现

import org.springframework.stereotype.Component;@Component
public class CreditScoreModule implements RiskModule {@Overridepublic void check() {System.out.println("信用评分模块风控校验...");}
}@Component
public class CreditLimitModule implements RiskModule {@Overridepublic void check() {System.out.println("额度计算模块风控校验...");}
}

5.5. 具体中介者实现(协调模块)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class RiskMediatorImpl implements RiskMediator {// 非构造函数注入@Autowiredprivate CreditScoreModule creditScoreModule;@Autowiredprivate CreditLimitModule creditLimitModule;@Overridepublic void execute(String action) {switch (action) {case "creditCheck":creditScoreModule.check();break;case "limitCheck":creditLimitModule.check();break;case "allCheck":creditScoreModule.check();creditLimitModule.check();break;default:System.out.println("未知操作");}}
}

5.6. 业务调用示例(Service)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class RiskService {@Autowiredprivate RiskMediator riskMediator;public void performRiskCheck() {System.out.println("开始风控校验...");riskMediator.execute("allCheck");System.out.println("风控校验完成");}
}

5.7. Spring Boot 主程序测试

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class RiskControlApplication implements CommandLineRunner {@Autowiredprivate RiskService riskService;public static void main(String[] args) {SpringApplication.run(RiskControlApplication.class, args);}@Overridepublic void run(String... args) throws Exception {riskService.performRiskCheck();}
}

5.8. 运行结果

复制编辑
开始风控校验...
信用评分模块风控校验...
额度计算模块风控校验...
风控校验完成

说明

  • 中介者对象负责协调多个风控模块,调用对应方法完成协作。
  • 如果以后需要新增风控模块,只需在中介者类中添加对应依赖并扩展 execute 方法即可。
  • 解耦风控模块之间的直接调用,实现灵活协作。

6. 中介者设计模式思考

6.1. 中介者设计模式常和以下设计模式组合使用,提升系统解耦性、灵活性和可维护性?

设计模式

作用

组合理由

观察者模式

事件通知,模块状态变更监听

松耦合,异步通知

策略模式

不同处理策略动态切换

灵活行为管理

命令模式

请求封装,支持撤销、排队

请求管理解耦

责任链模式

按顺序处理请求

流程控制与模块责任划分

工厂模式

创建模块实例

解耦模块实例化

状态模式

根据状态改变行为

简化状态管理,增强灵活性

6.1.1. 观察者模式(Observer Pattern)

  • 场景:中介者作为事件中心,监听模块状态变化并通知相关模块。
  • 组合效果:模块状态变化由中介者发起事件通知,避免模块间直接依赖,实现松耦合。

6.1.2. 策略模式(Strategy Pattern)

  • 场景:中介者根据不同场景或条件,动态选择不同的处理策略。
  • 组合效果:中介者协调不同策略,提升行为灵活性和可扩展性。

6.1.3. 命令模式(Command Pattern)

  • 场景:将请求封装成命令对象,中介者负责调用命令,支持请求排队、撤销等操作。
  • 组合效果:使请求调用和执行解耦,中介者集中管理命令执行。

6.1.4. 责任链模式(Chain of Responsibility Pattern)

  • 场景:多个模块按顺序处理请求,中介者组织责任链,协调链上的处理步骤。
  • 组合效果:流程化请求处理,增强模块间协作的灵活控制。

6.1.5. 工厂模式(Factory Pattern)

  • 场景:中介者创建或获取模块实例,通过工厂解耦模块创建细节。
  • 组合效果:提高模块实例管理灵活性,便于模块替换和扩展。

6.1.6. 状态模式(State Pattern)

  • 场景:中介者根据系统或模块状态变化,动态调整模块行为。
  • 组合效果:将状态和行为分离,简化中介者的决策逻辑。

6.2. 中介者和观察者模式实战示例

6.2.1. 适用场景对比

模式

适用场景

特点

中介者模式

多个组件之间复杂协作、行为依赖,强交互逻辑需要统一协调

强中心化,便于流程控制、逻辑清晰,但中介者本身易变复杂

观察者模式

一个对象状态变化需通知多个对象,多个模块监听某事件或行为

弱耦合、支持异步,适合事件驱动架构,但流程控制不集中,追踪困难

6.2.2. ✅ 场景 1:金融风控审批系统(使用中介者模式)

业务背景: 用户提交贷款申请,需依次经过以下模块:

  • 黑名单检查
  • 身份实名认证
  • 反欺诈评分
  • 授信额度计算
    这些模块相互有顺序依赖,并存在交互控制。

✅ 实现方式(中介者模式):

@Component
public class RiskMediator {@Autowired private BlacklistChecker blacklistChecker;@Autowired private IdentityVerifier identityVerifier;@Autowired private AntiFraudEngine antiFraudEngine;@Autowired private CreditScoreCalculator creditScoreCalculator;public RiskResult process(UserApplyDTO apply) {if (!blacklistChecker.check(apply)) return RiskResult.reject("黑名单");if (!identityVerifier.verify(apply)) return RiskResult.reject("身份校验失败");FraudResult fraud = antiFraudEngine.analyze(apply);if (fraud.isHighRisk()) return RiskResult.reject("欺诈嫌疑");return creditScoreCalculator.calculate(apply);}
}

所有风控组件之间不直接通信,由 RiskMediator 协调。

6.2.3. ✅ 场景 2:用户注册发送通知(使用观察者模式)

业务背景: 用户注册成功后,需要:

  • 发送欢迎短信
  • 推送用户画像同步任务
  • 发放注册优惠券

这三个操作彼此独立,不影响主流程。

✅ 实现方式(观察者模式 + Spring Event):

定义事件对象:

public class UserRegisterEvent extends ApplicationEvent {private final Long userId;public UserRegisterEvent(Object source, Long userId) {super(source);this.userId = userId;}public Long getUserId() { return userId; }
}

发布事件:

@Component
public class UserService {@Autowired private ApplicationEventPublisher publisher;public void register(UserDTO dto) {// 注册逻辑...publisher.publishEvent(new UserRegisterEvent(this, dto.getId()));}
}

监听器(观察者):

@Component
public class WelcomeSmsListener {@EventListenerpublic void onRegister(UserRegisterEvent event) {// 发送短信}
}@Component
public class ProfileSyncListener {@EventListenerpublic void onRegister(UserRegisterEvent event) {// 同步画像}
}

Spring 自动管理监听器注册,模块间完全解耦,扩展方便。

6.3. ✅ 中介者和观察者模式总结

目标

推荐模式

理由

统一控制业务流程

中介者模式

控制逻辑集中,适合复杂流程协调

模块间异步通知

观察者模式

低耦合、事件驱动、支持多个订阅方

需要响应式扩展通知

观察者模式

任意监听器可接入或移除,灵活扩展

模块依赖顺序较强

中介者模式

控制好执行顺序,模块逻辑依赖清晰

博文参考


http://www.hkcw.cn/article/SulKMldMMk.shtml

相关文章

20250602在荣品的PRO-RK3566开发板的Android13下的uboot启动阶段配置BOOTDELAY为10s

20250602在荣品的PRO-RK3566开发板的Android13下的uboot启动阶段配置BOOTDELAY为10s 2025/6/2 18:15 缘起:有些时候,需要在uboot阶段做一些事情。 于是,希望在荣品的PRO-RK3566开发板的Android13下的uboot启动停下。 1、【原始的LOG&#xff…

汽车安全体系:FuSa、SOTIF、Cybersecurity 从理论到实战

汽车安全:功能安全(FuSa)、预期功能安全(SOTIF)与网络安全(Cybersecurity) 从理论到实战的安全体系 引言:自动驾驶浪潮下的安全挑战 随着自动驾驶技术从L2向L4快速演进,汽车安全正从“机械可靠…

学习经验分享【40】目标检测热力图制作

目标检测热力图在学术论文(尤其是计算机视觉、深度学习领域)中是重要的可视化分析工具和论证辅助手段,可以给论文加分不少。主要作用一是增强论文的可解释性与说服力:论文中常需解释模型 “如何” 或 “为何” 检测到目标&#xf…

C++ 检查一条线是否与圆接触或相交(Check if a line touches or intersects a circle)

给定一个圆的圆心坐标、半径 > 1 的圆心坐标以及一条直线的方程。任务是检查给定的直线是否与圆相交。有三种可能性: 1、线与圆相交。 2、线与圆相切。 3、线在圆外。 注意:直线的一般方程是 a*x b*y c 0,因此输入中只给出常数 a、b、…

判断用户输入昵称是否存在(Python)

一、运行结果 二、源代码 # 创建一个存储昵称的列表; name_list [章鱼, 张愚, 宇文弑]# 循环输入判断用户输入昵称是否存在 while True:# 获取用户输入的昵称;name input(请输入昵称:)# 判断昵称是否存在;if name in name_list…

RAG理论基础总结

目录 概念 流程 文档收集和切割 读取文档 转换文档 写入文档 向量转换和存储 搜索请求构建 向量存储工作原理 向量数据库 文档过滤和检索 检索前 检索 检索后 查询增强和关联 QuestionAnswerAdvisor查询增强 高级RAG架构 自纠错 RAG(C-RAG&#xf…

pikachu靶场通关笔记09 XSS关卡05-DOM型XSS-X

目录 一、XSS 二、DOM型XSS 三、源码分析 1、打开DOM-X型XSS关卡 2、XSS探测 3、源码分析 四、渗透实战 1、Payload1 2、Payload2 3、Payload3 五、DOM型XSS与DOM-X型XSS区别 本系列为通过《pikachu靶场通关笔记》的XSS攻击关卡(共10关)渗透集合&#xf…

3. TypeScript 中的数据类型

在 TypeScript 中,类型(Types)允许你定义并强制执行应用中数据的结构。通过使用类型,你可以在编译阶段捕捉错误,而不是等到运行时才发现,从而让代码更加可预测,也更不容易出现 bug。TypeScript …

【Java Web】速通Tomcat

参考笔记:JavaWeb 速通Tomcat_tomcat部署java项目-CSDN博客 目录 一、Tomcat服务 1. 下载和安装 2. 启动Tomcat服务 3. 启动Tomcat服务的注意事项 4. 关闭Tomcat服务 二、Tomcat的目录结构 1. bin 🌟 2. conf 🌟 3. lib 4. logs 5. temp 6. webapps 7. work 三、Web项目…

从零实现Python扫雷游戏:完整开发指南与深度解析

目录 一、游戏架构设计 1.1 核心组件 1.2 类结构设计 二、核心算法实现 2.1 地雷生成算法 2.2 数字计算算法 2.3 空白区域展开算法 三、图形界面开发 3.1 主界面布局 3.2 交互事件处理 左键点击事件 右键点击事件 3.3 游戏状态显示 四、游戏功能扩展 4.1 多难度…

hooks组件-useState

hooks组件-useState hook组件的本质就是函数组件,但是基于各种hook让其动态化! 常用hook: useReducer:redux useCallback useMemo:去做一些优化。 useRef:使用ref useImperativeHandle:拿到子组…

X浏览器APP:轻巧快捷,畅享极速浏览

在移动互联网时代,浏览器作为我们获取信息、娱乐和社交的重要工具,其性能和功能直接影响着我们的使用体验。X浏览器APP正是这样一款专为移动设备设计的轻巧快捷的网络浏览器,它凭借独特的核心引擎和多项实用功能,为用户提供了极速…

一种基于性能建模的HADOOP配置调优策略

1.摘要 作为分布式系统基础架构的Hadoop为应用程序提供了一组稳定可靠的接口。该文作者提出了一种基于集成学习建模的Hadoop配置参数调优的方法。实验结果表明,该性能模型可以准确预测MapReduce应用程序的运行时间。采用提出的Hadoop配置参数方法调优后&#xff0c…

【001】利用github搭建静态网站_essay

文章目录 1. 简介2. 先了解网址规则2.1 文件及网址形式2.2 相互访问 3. 搭建网页的过程3.1 网页文件3.2 github搭建仓库及文件上传3.3 搭建网站 1. 简介 相信大家都有过想要自己搭建一个稳定可靠的网站,github是一个不错的选择,本来国内有gitee可以搭建…

太极APP:免Root,畅享Xposed模块的神奇魅力

在安卓系统中,Xposed框架一直以其强大的功能和高度的自定义能力受到众多用户的喜爱。然而,传统的Xposed框架需要Root权限和复杂的刷机操作,这使得许多普通用户望而却步。太极APP的出现,打破了这一限制,它为用户提供了一…

大学专业解读——电子信息

家里娃要高考了,面临专业和学校选择的问题。虽然我们家长做为职场人已经工作超过30年,但实际上对于专业和就业的问题,也不是太懂,网上有很多营销号在讲专业的志愿填报,但信息都比较碎片。所以,抽出一点时间…

实验一:PyTorch基本操作实验

import torch # PyTorch中初始化矩阵常见有以下几种方法 # 1. 直接使用固定值初始化 # M torch.tensor([[1.0, 2.0, 3.0]]) # 1x3矩阵 # 2. 随机初始化 # M torch.rand(1, 3) # 1x3矩阵,元素在0-1之间均匀分布 # M torch.randn(1, 3) # 1x3矩阵,元…

深入理解 C++ 中的 list 容器:从基础使用到模拟实现

一、list 的底层数据结构与核心特性 1.1 双向循环链表的物理结构 节点定义&#xff1a;每个节点包含三个部分 template <typename T> struct ListNode {T data; // 存储的数据ListNode* prev; // 指向前驱节点的指针ListNode* next; // 指向后继节点的指针L…

【iOS】YYModel源码解析

YYModel源码解析 文章目录 YYModel源码解析前言YYModel性能优势YYModel简介YYClassInfo解析YYClassIvarInfo && objc_ivarYYClassMethodInfo && objc_methodYYClassPropertyInfo && property_tYYClassInfo && objc_class YYClassInfo的初始化细…

nssctf第二题[SWPUCTF 2021 新生赛]简简单单的逻辑

这是题目&#xff0c;下载后得到一个python文件,打开 解读代码&#xff1a; for i in range(len(list)):key (list[i]>>4)((list[i] & 0xf)<<4)result str(hex(ord(flag[i])^key))[2:].zfill(2)list[i]>>4&#xff1a;从列表中取数字同时高4位向右位…