Spring + 设计模式 (二十) 行为型 - 中介者模式

中介者模式

引言

中介者模式是一种行为型设计模式,旨在通过一个中介对象来封装一组对象之间的交互,从而降低它们之间的直接耦合。想象一个繁忙的机场控制塔,飞机之间无需直接通信,而是通过塔台协调起飞、降落和航线。中介者模式的核心思想是将复杂的多对多交互转化为一对多的集中式管理,增强系统的可维护性和扩展性。在企业级开发中,这种模式特别适用于处理模块间复杂的通信逻辑,如事件处理、消息分发或组件协作。它的魅力在于将混乱的网状依赖简化为清晰的星型结构,让代码更易于理解和修改。

实际开发中的用途

中介者模式在实际开发中广泛应用于需要协调多个对象交互的场景。它解决了对象间直接通信导致的高耦合问题,尤其在以下场景中大放异彩:

  • 事件驱动系统:如 GUI 界面开发,按钮、输入框等组件通过中介者(如控制器)协调动作。
  • 微服务通信:服务间通过消息队列或事件总线(如 Kafka、RabbitMQ)间接交互。
  • 模块化系统:如订单系统中的支付、库存、物流模块,通过中介者统一协调。

以电商订单处理为例,假设订单创建后需要通知支付、库存和物流模块。如果每个模块直接调用彼此,代码将变成一团乱麻。使用中介者模式,订单服务作为中介者接收订单请求,并协调支付扣款、库存扣减和物流调度。这种方式不仅降低了模块间的耦合,还便于新增模块(如通知模块)或修改逻辑(如增加审批流程)。中介者模式的核心价值在于将交互逻辑集中化,使系统更易扩展和维护。

示例场景:一个简单的聊天室应用,用户发送消息后,消息需广播给所有在线用户。如果用户直接相互通信,代码将因用户数量增加而变得复杂。通过引入一个聊天室中介者,所有消息都通过中介者分发,用户只需与中介者交互,逻辑清晰且易于扩展。

Spring 源码中的应用

在 Spring 框架中,中介者模式的一个典型应用体现在 Spring 事件机制 (ApplicationEvent 和 ApplicationListener)中。Spring 的事件发布与监听机制通过 ApplicationEventPublisher 作为中介者,协调事件的发布者和监听者之间的交互,避免了它们之间的直接依赖。

源码分析

以 Spring Core 的 ApplicationEventPublisher 为例,位于 org.springframework.context 包中,其核心实现类之一是 AbstractApplicationContext

以下是关键源码片段摘自 Spring Framework(AbstractApplicationContext.java):

java 复制代码
@Override
public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
}

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    // 确保事件对象是 ApplicationEvent 的实例
    ApplicationEvent applicationEvent = (event instanceof ApplicationEvent ? 
        (ApplicationEvent) event : new PayloadApplicationEvent<>(this, event));
    
    // 获取事件多播器并发布事件
    getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    
    // 如果存在父上下文,继续传播事件
    if (this.parent != null) {
        // 省略父上下文处理逻辑
    }
}

分析

  • 中介者角色ApplicationEventPublisher(具体实现为 AbstractApplicationContext)充当中介者,负责接收事件(如 ContextRefreshedEvent)并分发给所有注册的监听者。
  • 参与者解耦 :事件发布者(如 Spring 容器)无需知道有哪些监听者,监听者(如自定义 ApplicationListener)也无需关心事件来源,只需实现监听接口。这种一对多的通信完全通过中介者协调。
  • 问题解决:该机制解耦了事件发布与处理逻辑,使得 Spring 容器可以灵活扩展。例如,开发者可以自定义事件和监听器,实现启动后初始化、配置变更通知等功能。
  • 代码体现getApplicationEventMulticaster().multicastEvent 是中介者模式的核心,事件多播器(ApplicationEventMulticaster)遍历所有监听者并调用其 onApplicationEvent 方法,完成事件分发。

这种设计不仅降低了模块间的耦合,还支持异步事件处理(通过配置 TaskExecutor),体现了中介者模式在高并发场景下的灵活性。Spring 的事件机制广泛应用于容器生命周期管理、Bean 加载通知等场景,是中介者模式的经典实现。

Spring Boot 代码案例

以下是一个基于 Spring Boot的案例,模拟一个订单处理系统,通过中介者模式协调支付、库存和物流模块的交互。案例展示了如何利用 Spring 的事件机制实现中介者模式,解决模块间高耦合问题。

案例背景

在一个电商系统中,创建订单后需要触发支付扣款、库存扣减和物流调度。使用中介者模式,订单服务作为中介者发布订单创建事件,各模块监听事件并执行相应逻辑。

代码实现

java 复制代码
// 订单事件
public class OrderCreatedEvent extends ApplicationEvent {
    private final String orderId;

    public OrderCreatedEvent(Object source, String orderId) {
        super(source);
        this.orderId = orderId;
    }

    public String getOrderId() {
        return orderId;
    }
}

// 支付服务监听器
@Component
public class PaymentListener implements ApplicationListener<OrderCreatedEvent> {
    @Override
    public void onApplicationEvent(OrderCreatedEvent event) {
        System.out.println("Processing payment for order: " + event.getOrderId());
        // 模拟支付逻辑
    }
}

// 库存服务监听器
@Component
public class InventoryListener implements ApplicationListener<OrderCreatedEvent> {
    @Override
    public void onApplicationEvent(OrderCreatedEvent event) {
        System.out.println("Deducting inventory for order: " + event.getOrderId());
        // 模拟库存扣减逻辑
    }
}

// 物流服务监听器
@Component
public class LogisticsListener implements ApplicationListener<OrderCreatedEvent> {
    @Override
    public void onApplicationEvent(OrderCreatedEvent event) {
        System.out.println("Scheduling logistics for order: " + event.getOrderId());
        // 模拟物流调度逻辑
    }
}

// 订单服务(中介者)
@Service
public class OrderService {
    private final ApplicationEventPublisher eventPublisher;

    public OrderService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void createOrder(String orderId) {
        System.out.println("Creating order: " + orderId);
        // 发布订单创建事件
        eventPublisher.publishEvent(new OrderCreatedEvent(this, orderId));
    }
}

// 主应用
@SpringBootApplication
public class MediatorPatternApplication {
    public static void main(String[] args) {
        SpringApplication.run(MediatorPatternApplication.class, args);
    }
}

// 测试控制器
@RestController
public class OrderController {
    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping("/orders")
    public String createOrder(@RequestBody Map<String, String> request) {
        String orderId = request.get("orderId");
        orderService.createOrder(orderId);
        return "Order created: " + orderId;
    }
}

代码说明

  • 中介者模式体现OrderService 利用 ApplicationEventPublisher 作为中介者,发布 OrderCreatedEvent 事件。支付、库存和物流模块通过实现 ApplicationListener 监听事件,各自处理逻辑,模块间无需直接调用。
  • 优势
    • 低耦合:各模块只依赖事件接口,与其他模块无直接交互。
    • 易扩展:新增模块(如通知服务)只需实现新的监听器,无需修改现有代码。
    • 企业级适用性 :Spring 的事件机制支持异步处理(通过 @Async),适合高并发场景。
  • 运行效果 :通过 POST 请求 /orders 接口创建订单,控制台将依次输出订单创建、支付、库存和物流的处理日志,逻辑清晰且模块独立。

相似的设计模式对比

中介者模式与 观察者模式(Observer Pattern)在某些场景下有相似之处,但它们的侧重点和实现方式不同。以下是对比分析:

  • 中介者模式
    • 关键词:集中化、协调、解耦、复杂交互。
    • 说明:通过一个中介者对象协调多个对象间的交互,降低直接依赖,适用于复杂的多对多通信场景。
  • 观察者模式
    • 关键词:一对多、通知、松耦合、状态变化。
    • 说明:定义了一种一对多的依赖关系,当主体状态变化时,自动通知所有观察者,适用于状态变化的广播场景。

对比表格

特性 中介者模式 观察者模式
核心思想 通过中介者协调对象间交互 主体状态变化时通知观察者
耦合度 较低,对象只与中介者交互 较低,观察者只与主体交互
交互复杂度 适合复杂多对多交互 适合简单一对多通知
典型场景 聊天室、事件总线、模块协调 发布-订阅、状态监控、事件通知
Spring 中的实现 ApplicationEventPublisher ApplicationListener(部分场景)

代码对比

以下通过一个简单聊天室功能对比两者的实现差异。

中介者模式实现
java 复制代码
// 中介者接口
public interface ChatMediator {
    void sendMessage(String message, User user);
}

// 具体中介者
public class ChatRoomMediator implements ChatMediator {
    private List<User> users = new ArrayList<>();

    public void addUser(User user) {
        users.add(user);
    }

    @Override
    public void sendMessage(String message, User sender) {
        for (User user : users) {
            if (user != sender) {
                user.receiveMessage(message);
            }
        }
    }
}

// 用户类
public class User {
    private String name;
    private ChatMediator mediator;

    public User(String name, ChatMediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }

    public void sendMessage(String message) {
        mediator.sendMessage(message, this);
    }

    public void receiveMessage(String message) {
        System.out.println(name + " received: " + message);
    }
}
观察者模式实现
java 复制代码
// 主体接口
public interface Subject {
    void addObserver(Observer observer);
    void notifyObservers(String message);
}

// 具体主体
public class ChatRoomSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

    public void sendMessage(String message) {
        notifyObservers(message);
    }
}

// 观察者接口
public interface Observer {
    void update(String message);
}

// 具体观察者
public class ChatUser implements Observer {
    private String name;

    public ChatUser(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received: " + message);
    }
}

差异分析

  • 中介者模式ChatRoomMediator 集中管理消息分发逻辑,用户通过中介者发送和接收消息,适合需要协调复杂交互的场景(如过滤消息、权限控制)。
  • 观察者模式ChatRoomSubject 直接通知所有观察者,逻辑简单,适合状态变化广播(如所有用户收到相同消息)。但若需复杂逻辑(如部分用户接收),代码会变得繁琐。
  • 适用性:中介者模式更适合需要集中控制的场景,而观察者模式适合简单的通知机制。

总结

中介者模式是一把解耦的利刃,通过将复杂的对象交互集中到中介者中,将网状依赖转化为清晰的星型结构。它的核心价值在于降低系统耦合度、提升扩展性,特别适合事件驱动、模块化或高并发场景。在 Spring 框架中,ApplicationEventPublisher 是中介者模式的典范,优雅地实现了事件发布与监听的解耦,广泛应用于容器管理和业务扩展。与观察者模式相比,中介者模式在处理复杂交互时更具优势,但需权衡中介者的复杂度。实际开发中,善用中介者模式可以让代码如行云流水,既灵活又健壮。开发者应深刻理解其思想,将其融入系统设计中,打造优雅且可维护的架构。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢

相关推荐
程序员小陈在成都29 分钟前
Spring Ioc源码引入:什么是IoC,IoC解决了什么问题
spring
bug菌1 小时前
面十年开发候选人被反问:当类被标注为@Service后,会有什么好处?我...🫨
spring boot·后端·spring
麓殇⊙1 小时前
设计模式--桥接模式详解
设计模式·桥接模式
学习机器不会机器学习2 小时前
深入浅出JavaScript常见设计模式:从原理到实战(1)
开发语言·javascript·设计模式
阿杜杜不是阿木木3 小时前
03.使用spring-ai玩转MCP
java·人工智能·spring boot·spring·mcp·spring-ai
Stimd3 小时前
【重写SpringFramework】声明式事务上:构建事务切面(chapter 4-5)
java·后端·spring
caihuayuan43 小时前
【docker&redis】用docker容器运行单机redis
java·大数据·sql·spring·课程设计
学编程的小程5 小时前
Spring MVC深度解析:从原理到实战
java·spring·mvc
zuckzhao955 小时前
Spring Security入门学习(一)Helloworld项目
java·学习·spring