Appearance
中介者模式 (Mediator)
一、定义
一句话概括:用一个中介对象来封装一系列对象之间的交互,使各对象之间不需要显式地相互引用,从而降低耦合。
官方定义:Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
二、解决的问题
2.1 问题场景
在复杂的系统中,多个对象之间存在网状交互关系。例如:
- 聊天室:多个用户互相发送消息
- GUI 组件:按钮、文本框、下拉列表之间的联动
- 微服务调用:多个服务之间的相互调用
2.2 不用中介者模式会怎样?
java
// 反例:多个对象直接互相引用
class User {
private List<User> contacts; // 每个用户维护所有联系人
public void sendMessage(String msg, User receiver) {
receiver.receiveMessage(msg, this);
}
}
// 问题:每个用户需要知道所有其他用户,形成复杂的网状结构
// 新增用户类型需要修改所有相关类问题:
- 对象之间形成网状耦合,牵一发而动全身
- 交互逻辑分散在各个对象中,难以理解和维护
- 新增参与对象需要修改多个已有对象
三、结构
3.1 角色组成
| 角色 | 说明 |
|---|---|
| Mediator(抽象中介者) | 定义通信接口,用于与各个 Colleague 通信 |
| ConcreteMediator(具体中介者) | 实现中介者接口,协调各个 Colleague 的交互 |
| Colleague(抽象同事类) | 持有中介者的引用,通过中介者与其他同事通信 |
| ConcreteColleague(具体同事类) | 实现具体业务逻辑,通过中介者通信 |
3.2 类图(ASCII)
┌──────────────┐ ┌──────────────┐
│ Mediator │◄────────│ Colleague │
├──────────────┤ ├──────────────┤
│ + notify() │ │ - mediator │
└──────┬───────┘ │ + send() │
│ │ + receive() │
▼ └──────┬───────┘
┌──────────────┐ │
│ConcreteMediator│ ┌────┴────┐
│ │ │ │
│ │ ▼ ▼
│ │ ┌──────────┐┌──────────┐
└──────────────┘ │Concrete ││Concrete │
│ColleagueA││ColleagueB│
└──────────┘└──────────┘四、代码实现
4.1 基础实现
java
// ==================== 中介者接口 ====================
interface ChatMediator {
void sendMessage(String message, User sender);
void addUser(User user);
}
// ==================== 具体中介者:聊天室 ====================
class ChatRoom implements ChatMediator {
private List<User> users = new ArrayList<>();
@Override
public void addUser(User user) {
users.add(user);
}
@Override
public void sendMessage(String message, User sender) {
for (User user : users) {
// 发送者不接收自己的消息
if (user != sender) {
user.receive(message, sender);
}
}
}
}
// ==================== 抽象同事类 ====================
abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void send(String message);
public abstract void receive(String message, User sender);
public String getName() {
return name;
}
}
// ==================== 具体同事类 ====================
class ChatUser extends User {
public ChatUser(ChatMediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println(name + " 发送消息: " + message);
mediator.sendMessage(message, this);
}
@Override
public void receive(String message, User sender) {
System.out.println(name + " 收到来自 " + sender.getName() + " 的消息: " + message);
}
}
// ==================== 客户端 ====================
public class MediatorDemo {
public static void main(String[] args) {
ChatMediator chatRoom = new ChatRoom();
User alice = new ChatUser(chatRoom, "Alice");
User bob = new ChatUser(chatRoom, "Bob");
User charlie = new ChatUser(chatRoom, "Charlie");
chatRoom.addUser(alice);
chatRoom.addUser(bob);
chatRoom.addUser(charlie);
alice.send("大家好!");
bob.send("Hello Alice!");
}
}4.2 进阶实现
4.2.1 GUI 组件交互
java
// 中介者:登录对话框
class LoginDialogMediator implements Mediator {
private JTextField usernameField;
private JPasswordField passwordField;
private JButton loginButton;
private JButton clearButton;
private JCheckBox rememberMe;
public void setComponents(JTextField username, JPasswordField password,
JButton login, JButton clear, JCheckBox remember) {
this.usernameField = username;
this.passwordField = password;
this.loginButton = login;
this.clearButton = clear;
this.rememberMe = remember;
}
@Override
public void notify(Component sender, String event) {
if (sender == loginButton) {
handleLogin();
} else if (sender == clearButton) {
usernameField.setText("");
passwordField.setText("");
} else if (sender == usernameField || sender == passwordField) {
// 用户名和密码都不为空时启用登录按钮
boolean enable = !usernameField.getText().isEmpty()
&& passwordField.getPassword().length > 0;
loginButton.setEnabled(enable);
}
}
private void handleLogin() {
String username = usernameField.getText();
String password = new String(passwordField.getPassword());
System.out.println("登录: " + username);
// 登录逻辑...
}
}4.2.2 Spring MVC 前端控制器
java
// Spring MVC 的 DispatcherServlet 是中介者模式的经典应用
// 它作为前端控制器,协调 HandlerMapping、HandlerAdapter、ViewResolver 等组件
@Configuration
class WebConfig implements WebMvcConfigurer {
// DispatcherServlet 作为中介者:
// 1. 请求到达 → DispatcherServlet
// 2. DispatcherServlet → HandlerMapping(找到处理器)
// 3. DispatcherServlet → HandlerAdapter(执行处理器)
// 4. DispatcherServlet → ViewResolver(解析视图)
// 5. DispatcherServlet → 返回响应
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor());
}
}
// 自定义中介者:订单协调器
class OrderCoordinator {
private InventoryService inventoryService;
private PaymentService paymentService;
private NotificationService notificationService;
public void placeOrder(Order order) {
// 统一协调各个服务
if (!inventoryService.checkStock(order.getProductId(), order.getQuantity())) {
throw new RuntimeException("库存不足");
}
inventoryService.reserveStock(order.getProductId(), order.getQuantity());
paymentService.processPayment(order.getPaymentInfo());
inventoryService.deductStock(order.getProductId(), order.getQuantity());
notificationService.sendOrderConfirmation(order.getUserId(), order.getId());
}
}4.3 生产级实现
Spring Boot 微服务协调器
java
// ==================== 订单事件枚举 ====================
enum OrderEvent {
ORDER_CREATED, PAYMENT_SUCCESS, PAYMENT_FAILED,
STOCK_RESERVED, STOCK_DEDUCTED, SHIPMENT_CREATED,
ORDER_COMPLETED, ORDER_CANCELLED
}
// ==================== 中介者接口 ====================
interface OrderMediator {
void onEvent(OrderEvent event, Order order);
}
// ==================== 具体中介者 ====================
@Service
class OrderMediatorImpl implements OrderMediator {
@Autowired private InventoryService inventoryService;
@Autowired private PaymentService paymentService;
@Autowired private ShipmentService shipmentService;
@Autowired private NotificationService notificationService;
@Autowired private OrderRepository orderRepository;
@Override
public void onEvent(OrderEvent event, Order order) {
switch (event) {
case ORDER_CREATED:
handleOrderCreated(order);
break;
case PAYMENT_SUCCESS:
handlePaymentSuccess(order);
break;
case PAYMENT_FAILED:
handlePaymentFailed(order);
break;
case STOCK_RESERVED:
handleStockReserved(order);
break;
case STOCK_DEDUCTED:
handleStockDeducted(order);
break;
case SHIPMENT_CREATED:
handleShipmentCreated(order);
break;
default:
break;
}
}
private void handleOrderCreated(Order order) {
try {
inventoryService.reserveStock(order);
paymentService.processPayment(order);
} catch (Exception e) {
order.setStatus("CANCELLED");
orderRepository.save(order);
notificationService.sendOrderFailedNotification(order);
}
}
private void handlePaymentSuccess(Order order) {
inventoryService.deductStock(order);
shipmentService.createShipment(order);
notificationService.sendPaymentSuccessNotification(order);
}
private void handlePaymentFailed(Order order) {
inventoryService.releaseStock(order);
order.setStatus("PAYMENT_FAILED");
orderRepository.save(order);
notificationService.sendPaymentFailedNotification(order);
}
private void handleStockReserved(Order order) {
order.setStatus("STOCK_RESERVED");
orderRepository.save(order);
}
private void handleStockDeducted(Order order) {
order.setStatus("STOCK_DEDUCTED");
orderRepository.save(order);
}
private void handleShipmentCreated(Order order) {
order.setStatus("SHIPPED");
orderRepository.save(order);
notificationService.sendShipmentNotification(order);
}
}
// ==================== 订单服务(同事类) ====================
@Service
class OrderService {
@Autowired private OrderMediator mediator;
@Autowired private OrderRepository orderRepository;
public Order createOrder(OrderRequest request) {
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setQuantity(request.getQuantity());
order.setStatus("CREATED");
order = orderRepository.save(order);
// 通过中介者协调后续流程
mediator.onEvent(OrderEvent.ORDER_CREATED, order);
return order;
}
}
// ==================== Controller ====================
@RestController
@RequestMapping("/api/orders")
class OrderController {
@Autowired private OrderService orderService;
@PostMapping
public Order createOrder(@RequestBody OrderRequest request) {
return orderService.createOrder(request);
}
}五、优缺点
优点
- 减少耦合:Colleague 只与 Mediator 通信,不需要知道其他 Colleague
- 简化交互:多对多交互变为一对多交互,逻辑集中在 Mediator 中
- 易于扩展:新增 Colleague 只需在 Mediator 中增加处理逻辑
- 集中控制:交互逻辑集中管理,便于维护和修改
缺点
- 中介者可能变得臃肿:随着系统复杂度增加,Mediator 可能成为"上帝类"
- 单点风险:如果 Mediator 出现故障,整个系统可能无法正常工作
- 间接性:所有通信都通过中介者,可能带来性能开销
六、适用场景
- GUI 组件交互:按钮、文本框、列表等组件之间的联动
- 聊天室系统:多用户消息转发
- 微服务编排:多个服务之间的协调调用
- 工作流引擎:审批流程的节点协调
- 空中交通管制:飞机与塔台之间的通信
- Spring MVC:DispatcherServlet 协调各组件
七、JDK / Spring 框架中的实际应用
| 框架 | 应用位置 | 说明 |
|---|---|---|
| JDK | java.util.Timer | 任务调度的中介者 |
| JDK | java.lang.reflect.Method.invoke() | 方法调用的中介者 |
| Spring MVC | DispatcherServlet | 前端控制器,协调各组件 |
| Spring Cloud | Eureka Server | 服务注册中心,服务发现的中介者 |
| Spring Cloud | Config Server | 配置中心,配置分发的中介者 |
| MyBatis | SqlSession | 协调 Executor 和 StatementHandler |
八、与其他模式的关系
与观察者模式
- 中介者模式可以结合观察者模式实现,Colleague 作为观察者,Mediator 作为被观察者
与门面模式
- 相似:都封装了子系统
- 区别:门面模式是单向调用(客户端 → 子系统),中介者模式是双向通信(Colleague ↔ Colleague)
与命令模式
- 中介者模式可以使用命令模式,将请求封装为命令对象在 Mediator 中传递
与代理模式
- 中介者可以看作是一种特殊的代理,代理了 Colleague 之间的通信
九、面试常见问题
Q1:中介者模式和观察者模式有什么区别?
A:中介者模式中,Colleague 之间的通信必须通过 Mediator 中转,通信是双向的;观察者模式中,Subject 状态变化时通知所有 Observer,通信是单向的(Subject → Observer)。中介者模式关注的是协调交互,观察者模式关注的是状态变化的通知。
Q2:中介者模式有什么缺点?如何避免?
A:随着系统复杂度增加,Mediator 可能变得臃肿,成为"上帝类"。可以通过以下方式避免:(1) 多个 Mediator 分工协作,按业务领域拆分;(2) 结合事件驱动架构,用事件总线减轻 Mediator 负担;(3) 使用有限状态机(FSM)管理复杂的交互逻辑。
Q3:Spring MVC 的 DispatcherServlet 是如何体现中介者模式的?
A:DispatcherServlet 作为前端控制器(中介者),接收所有 HTTP 请求,然后协调 HandlerMapping(找到处理器)、HandlerAdapter(执行处理器)、ViewResolver(解析视图)等组件,最终返回响应。各个组件之间不直接通信,都通过 DispatcherServlet 协调。
Q4:微服务架构中,服务网格(Service Mesh)和中介者模式有什么关系?
A:Service Mesh(如 Istio)本质上就是中介者模式在微服务领域的应用。Sidecar 代理(Envoy)作为中介者,拦截服务间的所有通信,提供负载均衡、服务发现、熔断、限流等功能,使服务本身不需要关心这些横切关注点。
