一、中介者模式核心定义
中介者模式是行为型设计模式的一种,核心目的是:
定义一个中介对象来封装一系列对象之间的交互,使原有对象无需直接相互引用,从而降低它们之间的耦合度;同时,使对象间的交互可以独立变化。
简单来说:用一个 "中间者" 代替多个对象之间的直接通信,所有对象只和中介者交互,中介者负责转发 / 协调对象间的请求 。
核心解决的问题
- 解耦组件依赖 :避免组件之间形成 "网状依赖"(A↔B、A↔C、B↔C),转为 "星型依赖"(A→中介者、B→中介者、C→中介者);
- 集中管理交互逻辑 :组件间的复杂交互规则统一在中介者中实现,而非分散在各个组件内部;
- 提升扩展性 :新增组件时,只需修改中介者的交互规则,无需修改原有组件;
- 简化维护 :交互逻辑集中管理,定位问题、修改规则更高效。
生活类比
- 场景 1 :机场塔台(最经典类比)
- 组件:各架飞机(起飞、降落、滑行);
- 中介者:机场塔台;
- 核心:飞机之间不直接通信(如 "我要降落,你先避让"),而是统一向塔台汇报状态,塔台协调所有飞机的行动,避免碰撞。
- 场景 2 :微信群聊
- 组件:群内每个成员;
- 中介者:微信群;
- 核心:成员不直接私聊(除非必要),而是在群里发消息,微信群(中介者)将消息转发给所有成员,实现多对多通信。
- 场景 3 :微服务网关
- 组件:用户服务、订单服务、支付服务;
- 中介者:API 网关;
- 核心:服务之间不直接调用,而是通过网关转发请求、协调调用顺序、处理熔断降级。
标准角色
| 角色 | 职责 | 类比(机场场景) | 代码定位 |
|---|---|---|---|
| 抽象中介者(Mediator) | 定义组件与中介者交互的接口(如注册组件、转发消息) | 塔台的工作规范(接收汇报、下达指令) | 接口 / 抽象类 |
| 具体中介者(ConcreteMediator) | 实现抽象中介者,持有所有组件引用,封装组件间的交互逻辑 | 具体的机场塔台(协调飞机起降) | 核心实现类(如ChatRoom、ServiceGateway) |
| 抽象同事类(Colleague) | 定义组件的统一接口,持有中介者引用,可向中介者发送消息 / 接收指令 | 飞机的通用规范(汇报状态、接收指令) | 接口 / 抽象类 |
| 具体同事类(ConcreteColleague) | 实现抽象同事类,与中介者交互,不直接与其他同事类通信 | 具体的飞机(客机、货机) | 业务组件类(如UserService、OrderService) |
核心 UML 类图

二、群聊中介者
以 "微信群聊" 为例,实现中介者模式的核心逻辑 ------ 这是理解中介者模式最直观的案例,所有用户(同事类)通过群聊(中介者)交互,不直接私聊。
-
步骤 1:定义抽象中介者(群聊规范)
/**
-
抽象中介者:群聊接口(定义注册用户、发送消息的规范)
/
public interface ChatMediator {
/*- 注册用户到群聊
*/
void registerUser(User user);
/**
- 转发消息(发送者→群聊→所有其他用户)
*/
void sendMessage(String message, User sender);
}
- 注册用户到群聊
-
-
步骤 2:定义抽象同事类(用户规范)
/**
-
抽象同事类:用户接口(持有群聊引用,可发送/接收消息)
*/
public abstract class User {
// 持有中介者(群聊)引用(核心:用户只和群聊交互)
protected ChatMediator mediator;
protected String username;public User(ChatMediator mediator, String username) {
this.mediator = mediator;
this.username = username;
// 注册到群聊
mediator.registerUser(this);
}/**
- 发送消息到群聊
*/
public abstract void send(String message);
/**
- 接收来自群聊的消息
*/
public abstract void receive(String message);
// Getter
public String getUsername() {
return username;
}
} - 发送消息到群聊
-
-
步骤 3:实现具体中介者(微信群)
import java.util.ArrayList;
import java.util.List;/**
-
具体中介者:微信群(封装用户间的消息转发逻辑)
*/
public class WeChatGroup implements ChatMediator {
// 持有所有用户引用(同事类)
private final List<User> users = new ArrayList<>();/**
- 注册用户(添加到群聊)
*/
@Override
public void registerUser(User user) {
if (!users.contains(user)) {
users.add(user);
System.out.println("【中介者-微信群】用户 " + user.getUsername() + " 加入群聊");
}
}
/**
- 转发消息(核心:中介者处理交互逻辑)
- 规则:发送者的消息转发给群内所有其他用户
*/
@Override
public void sendMessage(String message, User sender) {
System.out.println("\n【中介者-微信群】转发 " + sender.getUsername() + " 的消息:" + message);
// 遍历所有用户,排除发送者,转发消息
for (User user : users) {
if (user != sender) {
user.receive(message);
}
}
}
}
- 注册用户(添加到群聊)
-
-
步骤 4:实现具体同事类(普通用户 / 管理员)
/**
-
具体同事类1:普通用户
*/
public class NormalUser extends User {
public NormalUser(ChatMediator mediator, String username) {
super(mediator, username);
}/**
- 发送消息(只调用中介者的方法,不直接找其他用户)
*/
@Override
public void send(String message) {
System.out.println("【同事类-普通用户】" + username + " 发送消息:" + message);
mediator.sendMessage(message, this);
}
/**
- 接收中介者转发的消息
*/
@Override
public void receive(String message) {
System.out.println("【同事类-普通用户】" + username + " 接收消息:" + message);
}
}
- 发送消息(只调用中介者的方法,不直接找其他用户)
/**
-
具体同事类2:管理员用户(有特殊权限,如禁言)
*/
public class AdminUser extends User {
public AdminUser(ChatMediator mediator, String username) {
super(mediator, username);
}@Override
public void send(String message) {
System.out.println("【同事类-管理员】" + username + " 发送消息:" + message);
mediator.sendMessage(message, this);
}@Override
public void receive(String message) {
System.out.println("【同事类-管理员】" + username + " 接收消息:" + message);
}/**
- 管理员特殊操作(通过中介者执行,不直接操作用户)
*/
public void muteUser(User user) {
System.out.println("\n【同事类-管理员】" + username + " 禁言 " + user.getUsername());
// 中介者可扩展禁言逻辑,此处简化
System.out.println("【中介者-微信群】执行禁言操作:" + user.getUsername() + " 被禁言");
}
}
- 管理员特殊操作(通过中介者执行,不直接操作用户)
-
-
客户端(使用群聊中介者)
/**
-
客户端:测试群聊中介者模式
*/
public class MediatorClient {
public static void main(String[] args) {
// 1. 创建中介者(微信群)
ChatMediator weChatGroup = new WeChatGroup();// 2. 创建同事类(用户),自动注册到群聊 User user1 = new NormalUser(weChatGroup, "张三"); User user2 = new NormalUser(weChatGroup, "李四"); User admin = new AdminUser(weChatGroup, "管理员"); // 3. 用户发送消息(只和中介者交互,不直接找其他用户) user1.send("大家好,我是张三!"); user2.send("张三你好,我是李四~"); admin.send("欢迎新成员加入!"); // 4. 管理员执行特殊操作(通过中介者) ((AdminUser) admin).muteUser(user1);}
}
-
输出结果
【中介者-微信群】用户 张三 加入群聊
【中介者-微信群】用户 李四 加入群聊
【中介者-微信群】用户 管理员 加入群聊
【同事类-普通用户】张三 发送消息:大家好,我是张三!
【中介者-微信群】转发 张三 的消息:大家好,我是张三!
【同事类-普通用户】李四 接收消息:大家好,我是张三!
【同事类-管理员】管理员 接收消息:大家好,我是张三!
【同事类-普通用户】李四 发送消息:张三你好,我是李四~
【中介者-微信群】转发 李四 的消息:张三你好,我是李四~
【同事类-普通用户】张三 接收消息:张三你好,我是李四~
【同事类-管理员】管理员 接收消息:张三你好,我是李四~
【同事类-管理员】管理员 发送消息:欢迎新成员加入!
【中介者-微信群】转发 管理员 的消息:欢迎新成员加入!
【同事类-普通用户】张三 接收消息:欢迎新成员加入!
【同事类-普通用户】李四 接收消息:欢迎新成员加入!
【同事类-管理员】管理员 禁言 张三
【中介者-微信群】执行禁言操作:张三 被禁言
三、Spring 实战版(微服务网关中介者)
在业务开发中,中介者模式最核心的实战场景是微服务网关 / 服务编排------ 网关作为中介者,协调用户服务、订单服务、支付服务的交互,避免服务间直接耦合。
-
依赖准备(Spring Boot)
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>3.2.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> -
核心模型定义
import lombok.Data;
/**
- 服务请求上下文(传递请求参数、响应结果)
*/
@Data
public class ServiceContext {
private String userId; // 用户ID
private String orderId; // 订单ID
private double amount; // 金额
private String result; // 处理结果
private String errorMsg; // 错误信息
}
/**
- 服务类型枚举
*/
public enum ServiceType {
USER_SERVICE, // 用户服务
ORDER_SERVICE, // 订单服务
PAY_SERVICE // 支付服务
}
- 服务请求上下文(传递请求参数、响应结果)
-
抽象中介者(服务网关)
/**
-
抽象中介者:服务网关接口(协调各微服务交互)
/
public interface ServiceGatewayMediator {
/*- 注册微服务到网关
*/
void registerService(MicroService service);
/**
- 转发请求到指定服务
*/
ServiceContext forwardRequest(ServiceType serviceType, ServiceContext context);
/**
- 编排服务调用(如:创建订单→扣减库存→支付)
*/
ServiceContext orchestrateOrderFlow(ServiceContext context);
}
- 注册微服务到网关
-
-
抽象同事类(微服务)
/**
-
抽象同事类:微服务接口(持有网关引用,处理请求)
*/
public abstract class MicroService {
// 持有中介者(网关)引用
protected ServiceGatewayMediator mediator;
protected ServiceType serviceType;public MicroService(ServiceGatewayMediator mediator, ServiceType serviceType) {
this.mediator = mediator;
this.serviceType = serviceType;
// 注册到网关
mediator.registerService(this);
}/**
- 处理网关转发的请求
*/
public abstract ServiceContext handleRequest(ServiceContext context);
// Getter
public ServiceType getServiceType() {
return serviceType;
}
} - 处理网关转发的请求
-
-
具体中介者(API 网关实现)
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;/**
-
具体中介者:API网关(核心:协调微服务交互)
*/
@Slf4j
@Component
public class ApiGateway implements ServiceGatewayMediator {
// 存储所有注册的微服务(服务类型→服务实例)
private final Map<ServiceType, MicroService> serviceMap = new HashMap<>();/**
- 注册微服务到网关
*/
@Override
public void registerService(MicroService service) {
serviceMap.put(service.getServiceType(), service);
log.info("【中介者-API网关】注册服务:{}", service.getServiceType());
}
/**
- 转发请求到指定服务(核心:中介者路由请求)
*/
@Override
public ServiceContext forwardRequest(ServiceType serviceType, ServiceContext context) {
log.info("【中介者-API网关】转发请求到 {},用户ID:{},订单ID:{}",
serviceType, context.getUserId(), context.getOrderId());
// 获取目标服务
MicroService service = serviceMap.get(serviceType);
if (service == null) {
context.setErrorMsg("服务不存在:" + serviceType);
return context;
}
// 转发请求到服务
return service.handleRequest(context);
}
/**
-
编排订单流程(复杂交互逻辑集中在中介者)
-
流程:校验用户→创建订单→支付订单
*/
@Override
public ServiceContext orchestrateOrderFlow(ServiceContext context) {
log.info("【中介者-API网关】开始编排订单流程,订单ID:{}", context.getOrderId());// 1. 转发到用户服务,校验用户
ServiceContext userContext = forwardRequest(ServiceType.USER_SERVICE, context);
if (userContext.getErrorMsg() != null) {
log.error("【中介者-API网关】用户校验失败:{}", userContext.getErrorMsg());
return userContext;
}// 2. 转发到订单服务,创建订单
ServiceContext orderContext = forwardRequest(ServiceType.ORDER_SERVICE, userContext);
if (orderContext.getErrorMsg() != null) {
log.error("【中介者-API网关】创建订单失败:{}", orderContext.getErrorMsg());
return orderContext;
}// 3. 转发到支付服务,支付订单
ServiceContext payContext = forwardRequest(ServiceType.PAY_SERVICE, orderContext);
if (payContext.getErrorMsg() != null) {
log.error("【中介者-API网关】支付订单失败:{}", payContext.getErrorMsg());
return payContext;
}// 4. 流程完成
payContext.setResult("订单流程完成:用户校验通过→订单创建成功→支付成功,订单ID:" + context.getOrderId());
log.info("【中介者-API网关】订单流程完成,订单ID:{}", context.getOrderId());
return payContext;
}
}
- 注册微服务到网关
-
-
具体同事类(各微服务实现)
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/**
-
具体同事类1:用户服务(校验用户合法性)
*/
@Slf4j
@Component
public class UserService extends MicroService {
public UserService(ServiceGatewayMediator mediator) {
super(mediator, ServiceType.USER_SERVICE);
}/**
- 处理用户校验请求(只和网关交互,不直接调用其他服务)
*/
@Override
public ServiceContext handleRequest(ServiceContext context) {
log.info("【同事类-用户服务】校验用户:{}", context.getUserId());
// 模拟校验逻辑:用户ID以U开头则合法
if (context.getUserId() == null || !context.getUserId().startsWith("U")) {
context.setErrorMsg("用户ID非法:" + context.getUserId());
return context;
}
context.setResult("用户校验通过:" + context.getUserId());
return context;
}
}
- 处理用户校验请求(只和网关交互,不直接调用其他服务)
/**
-
具体同事类2:订单服务(创建订单)
*/
@Slf4j
@Component
public class OrderService extends MicroService {
public OrderService(ServiceGatewayMediator mediator) {
super(mediator, ServiceType.ORDER_SERVICE);
}@Override
public ServiceContext handleRequest(ServiceContext context) {
log.info("【同事类-订单服务】创建订单:{},金额:{}", context.getOrderId(), context.getAmount());
// 模拟创建逻辑:订单ID以O开头且金额>0则成功
if (context.getOrderId() == null || !context.getOrderId().startsWith("O")) {
context.setErrorMsg("订单ID非法:" + context.getOrderId());
return context;
}
if (context.getAmount() <= 0) {
context.setErrorMsg("订单金额非法:" + context.getAmount());
return context;
}
context.setResult("订单创建成功:" + context.getOrderId());
return context;
}
}
/**
-
具体同事类3:支付服务(支付订单)
*/
@Slf4j
@Component
public class PayService extends MicroService {
public PayService(ServiceGatewayMediator mediator) {
super(mediator, ServiceType.PAY_SERVICE);
}@Override
public ServiceContext handleRequest(ServiceContext context) {
log.info("【同事类-支付服务】支付订单:{},金额:{}", context.getOrderId(), context.getAmount());
// 模拟支付逻辑:金额>0则支付成功
if (context.getAmount() <= 0) {
context.setErrorMsg("支付金额非法:" + context.getAmount());
return context;
}
context.setResult("订单支付成功:" + context.getOrderId() + ",金额:" + context.getAmount());
return context;
}
}
-
-
客户端(Spring Boot 测试)
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;/**
-
客户端:测试微服务网关中介者
*/
@SpringBootApplication
public class SpringMediatorDemoApplication {
public static void main(String[] args) {
// 1. 启动Spring容器(自动注册网关和微服务)
ConfigurableApplicationContext context = SpringApplication.run(SpringMediatorDemoApplication.class, args);
ServiceGatewayMediator gateway = context.getBean(ApiGateway.class);// 2. 测试正常订单流程 System.out.println("======= 测试正常订单流程 ======="); ServiceContext normalContext = new ServiceContext(); normalContext.setUserId("U1001"); normalContext.setOrderId("O2001"); normalContext.setAmount(999.9); ServiceContext normalResult = gateway.orchestrateOrderFlow(normalContext); System.out.println("最终结果:" + normalResult.getResult()); // 3. 测试异常订单流程(金额非法) System.out.println("\n======= 测试异常订单流程(金额非法) ======="); ServiceContext errorContext = new ServiceContext(); errorContext.setUserId("U1002"); errorContext.setOrderId("O2002"); errorContext.setAmount(-100); // 非法金额 ServiceContext errorResult = gateway.orchestrateOrderFlow(errorContext); System.out.println("最终结果:" + errorResult.getErrorMsg()); context.close();}
}
-
输出结果
【中介者-API网关】注册服务:USER_SERVICE
【中介者-API网关】注册服务:ORDER_SERVICE
【中介者-API网关】注册服务:PAY_SERVICE
======= 测试正常订单流程 =======
【中介者-API网关】开始编排订单流程,订单ID:O2001
【中介者-API网关】转发请求到 USER_SERVICE,用户ID:U1001,订单ID:O2001
【同事类-用户服务】校验用户:U1001
【中介者-API网关】转发请求到 ORDER_SERVICE,用户ID:U1001,订单ID:O2001
【同事类-订单服务】创建订单:O2001,金额:999.9
【中介者-API网关】转发请求到 PAY_SERVICE,用户ID:U1001,订单ID:O2001
【同事类-支付服务】支付订单:O2001,金额:999.9
【中介者-API网关】订单流程完成,订单ID:O2001
最终结果:订单流程完成:用户校验通过→订单创建成功→支付成功,订单ID:O2001
======= 测试异常订单流程(金额非法) =======
【中介者-API网关】开始编排订单流程,订单ID:O2002
【中介者-API网关】转发请求到 USER_SERVICE,用户ID:U1002,订单ID:O2002
【同事类-用户服务】校验用户:U1002
【中介者-API网关】转发请求到 ORDER_SERVICE,用户ID:U1002,订单ID:O2002
【同事类-订单服务】创建订单:O2002,金额:-100.0
【中介者-API网关】创建订单失败:订单金额非法:-100.0
最终结果:订单金额非法:-100.0
四、中介者模式的核心特点与适用场景
优点
解耦组件依赖:组件间无需直接引用,所有交互通过中介者完成,降低耦合度;
集中管理交互逻辑:复杂的组件交互规则统一在中介者中实现,避免逻辑分散;
提升扩展性:新增组件时,只需修改中介者的注册 / 转发逻辑,无需修改原有组件;
简化维护:交互逻辑集中,定位问题、修改规则更高效;
支持多对多交互:中介者可轻松处理多个组件间的复杂通信(如群聊、服务编排)。
缺点中介者类膨胀:复杂系统中,中介者会封装大量交互逻辑,导致类过大、难以维护("上帝类" 问题);
性能瓶颈:所有交互都经过中介者,高并发场景下中介者可能成为性能瓶颈;
依赖集中:组件对中介者的依赖增强,中介者故障会影响所有组件;
调试复杂:交互逻辑集中在中介者,需跟踪中介者与多个组件的调用流程。
适用场景组件间形成网状依赖:如多个 GUI 组件(按钮、文本框、下拉框)交互、多个微服务调用;
多对多通信场景:如群聊、消息队列、事件总线;
服务编排 / 流程控制:如微服务网关、订单流程(创建→支付→发货)、审批流程;
框架底层设计:如 Spring 的 ApplicationContext(作为 Bean 之间的中介者)、Netty 的 EventLoop(作为 Channel 的中介者);
需要集中管控交互:如权限校验、日志记录、熔断降级(中介者统一处理)。
五、JDK/ Spring 中的原生应用(必须知道)
中介者模式在框架中应用广泛,以下是核心场景:
- Spring 核心容器(ApplicationContext)
- 抽象中介者:ApplicationContext;
- 具体中介者:AnnotationConfigApplicationContext、ClassPathXmlApplicationContext;
- 同事类:所有 Spring Bean;
- 核心逻辑:Bean 之间不直接依赖,而是通过 ApplicationContext 获取依赖(依赖注入),ApplicationContext 协调 Bean 的创建、初始化、销毁。
- Spring Cloud 网关(Spring Cloud Gateway/Zuul)
- 抽象中介者:GatewayFilter/RouteLocator;
- 具体中介者:DispatcherHandler(网关核心处理器);
- 同事类:各微服务;
- 核心逻辑:网关作为中介者,转发请求、协调服务调用、处理跨域 / 限流 / 熔断。
- Java AWT/Swing(GUI 组件)
- 抽象中介者:java.awt.EventQueue;
- 具体中介者:javax.swing.DefaultButtonModel;
- 同事类:按钮、文本框、下拉框等 GUI 组件;
- 核心逻辑:GUI 组件不直接交互,而是通过事件队列(中介者)处理用户操作。
- 消息中间件(RabbitMQ/Kafka)
- 抽象中介者:Exchange(交换机);
- 具体中介者:DirectExchange/TopicExchange;
- 同事类:生产者、消费者;
- 核心逻辑:生产者 / 消费者不直接通信,而是通过交换机(中介者)转发消息。
- Netty 事件循环(EventLoop)
- 抽象中介者:EventLoop;
- 具体中介者:NioEventLoop;
- 同事类:Channel/Handler;
- 核心逻辑:EventLoop 作为中介者,协调 Channel 的 I/O 事件、Handler 的执行。
六、中介者模式 vs 观察者模式
| 维度 | 中介者模式 | 观察者模式 |
|---|---|---|
| 核心目的 | 协调多个组件间的双向交互 | 实现一对多的单向通知 |
| 核心结构 | 中介者 + 多个同事类(星型依赖) | 主题 + 多个观察者(一对多依赖) |
| 交互方向 | 双向(组件→中介者→组件) | 单向(主题→观察者) |
| 触发方式 | 组件主动调用中介者 | 主题主动通知观察者 |
| 典型场景 | 群聊、服务网关、GUI 组件交互 | 事件通知、消息推送、状态监听 |
总结
- 中介者模式的核心是用一个中介者封装组件间的交互,将网状依赖转为星型依赖,降低组件耦合度;
- 核心角色包括抽象中介者(交互规范)、具体中介者(核心交互逻辑)、抽象同事类(组件规范)、具体同事类(业务组件);
- 业务开发中,中介者模式最实用的场景是微服务网关、服务编排、群聊 / 消息转发,需注意避免中介者类过度膨胀;
- 中介者模式的优点是解耦、集中管理交互,缺点是可能形成 "上帝类",需合理拆分中介者职责(如按功能拆分多个中介者)。
