Skip to content

中介者模式 (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);
    }
}

// 问题:每个用户需要知道所有其他用户,形成复杂的网状结构
// 新增用户类型需要修改所有相关类

问题:

  1. 对象之间形成网状耦合,牵一发而动全身
  2. 交互逻辑分散在各个对象中,难以理解和维护
  3. 新增参与对象需要修改多个已有对象

三、结构

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);
    }
}

五、优缺点

优点

  1. 减少耦合:Colleague 只与 Mediator 通信,不需要知道其他 Colleague
  2. 简化交互:多对多交互变为一对多交互,逻辑集中在 Mediator 中
  3. 易于扩展:新增 Colleague 只需在 Mediator 中增加处理逻辑
  4. 集中控制:交互逻辑集中管理,便于维护和修改

缺点

  1. 中介者可能变得臃肿:随着系统复杂度增加,Mediator 可能成为"上帝类"
  2. 单点风险:如果 Mediator 出现故障,整个系统可能无法正常工作
  3. 间接性:所有通信都通过中介者,可能带来性能开销

六、适用场景

  1. GUI 组件交互:按钮、文本框、列表等组件之间的联动
  2. 聊天室系统:多用户消息转发
  3. 微服务编排:多个服务之间的协调调用
  4. 工作流引擎:审批流程的节点协调
  5. 空中交通管制:飞机与塔台之间的通信
  6. Spring MVC:DispatcherServlet 协调各组件

七、JDK / Spring 框架中的实际应用

框架应用位置说明
JDKjava.util.Timer任务调度的中介者
JDKjava.lang.reflect.Method.invoke()方法调用的中介者
Spring MVCDispatcherServlet前端控制器,协调各组件
Spring CloudEureka Server服务注册中心,服务发现的中介者
Spring CloudConfig Server配置中心,配置分发的中介者
MyBatisSqlSession协调 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)作为中介者,拦截服务间的所有通信,提供负载均衡、服务发现、熔断、限流等功能,使服务本身不需要关心这些横切关注点。