《程序猿之设计模式实战 · 观察者模式》-LMLPHP

写在前面的话

本篇文章继续介绍一下观察者模式,这个在日常工作中接触还是挺多的,但和发布订阅模式又有什么不同呢?

相关文章:
《程序猿之设计模式实战 · 策略模式》
《程序猿之设计模式实战 · 装饰者模式》
《程序猿之设计模式实战 · 池化思想》


基础介绍

观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。这种模式常用于实现事件处理系统。

主要角色:

  1. 主题(Subject):被观察的对象,维护观察者的列表,并提供注册、注销观察者的方法。
  2. 观察者(Observer):对主题的变化感兴趣的对象,定义一个更新接口,以便接收主题的通知。

观察者模式的日常应用场景:

事件处理系统:如 GUI 应用中的按钮点击、文本框输入等事件的处理。

消息推送:社交媒体应用中,当用户发布新内容时,所有关注该用户的用户都会收到通知。

股票市场:当股票价格变化时,所有订阅该股票的投资者都会收到更新。

天气监测:天气预报应用中,用户可以订阅天气变化的通知。

日志系统:在日志框架中,多个观察者可以监听日志事件并执行相应的处理(如写入文件、发送邮件等)。


代码实现

Spring的事件用法就是典型的观察者模式。

实现步骤:

Step1、创建自定义事件

public class CustomEvent extends ApplicationEvent {
    private String message;

    public CustomEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

Step2、创建事件监听器

@Component
public class CustomEventListener {

    @EventListener
    public void handleCustomEvent(CustomEvent event) {
        System.out.println("Received custom event - Message: " + event.getMessage());
    }
}

Step3、创建事件发布者

@Component
public class EventPublisher {
    private final ApplicationEventPublisher publisher;

    public EventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void publish(String message) {
        CustomEvent event = new CustomEvent(this, message);
        publisher.publishEvent(event);
    }
}

Step4、合适的位置触发一下事件,例如下方的服务初始化。

@Component
public class AppRunner implements CommandLineRunner {

    private final EventPublisher eventPublisher;

    @Autowired
    public AppRunner(EventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    @Override
    public void run(String... args) throws Exception {
        eventPublisher.publish("Hello, Observer Pattern!");
    }
}

观察者&发布订阅

观察者模式和发布-订阅模式(Publish-Subscribe Pattern)有相似之处,但它们之间也存在一些关键的区别:

1、耦合度:

观察者模式:主题和观察者之间是直接的依赖关系。观察者需要知道主题的存在,并注册到主题中。

发布-订阅模式:发布者和订阅者之间是解耦的。发布者不需要知道任何订阅者的存在,反之亦然。它们通过一个中介(如消息代理)进行通信。

2、通信方式:

观察者模式:通常是同步的,观察者在主题状态变化时立即收到通知。

发布-订阅模式:可以是同步或异步的,发布者发布消息后,订阅者可以在稍后时间接收消息。

3、使用场景:

观察者模式:适用于一对多的关系,通常在同一个应用程序中使用。

发布-订阅模式:适用于分布式系统或微服务架构,允许不同的应用程序或服务之间进行通信。

总结:

观察者模式和发布-订阅模式都用于实现事件驱动的架构,但它们在耦合度、通信方式和使用场景上有所不同。选择哪种模式取决于具体的需求和应用场景。


补充说明

按前面内容所介绍的,好像发布订阅模式的使用场景更广,比如 RedisTemplate.convertAndSend 方法在 Spring 中用于将消息发送到 Redis 的某个频道。这种机制可以被视为一种发布-订阅模式的实现,而不是严格的观察者模式。又比如Kafka 中的生产者和消费者的交互属于典型的发布-订阅模式。

这里再分析比对一下两者。

发布-订阅模式

使用场景:适用于需要在不同组件之间进行松耦合通信的场景。比如,使用 Redis、Kafka 等消息中间件时,发布者和订阅者之间没有直接的依赖关系。

优点:可以轻松扩展,添加新的订阅者不需要修改发布者的代码,适合分布式系统。

观察者模式

使用场景:通常用于对象之间的直接关系,适合在同一应用程序内部进行事件通知。Spring 的事件机制就是一个典型的例子。

优点:实现简单,适合在内存中处理事件,适合小范围的事件传播。

总结一下:

发布-订阅模式:适合跨服务或组件的通信,使用消息中间件。

观察者模式:适合在同一应用程序内部的事件处理,使用 Spring 的事件机制。

这两种模式各有其适用场景,选择时可以根据具体需求来决定。


总结陈词

还是那句话,不用过多的纠结在用的是哪个设计模式,实现的是什么标准。

遇到实际问题能使用合适的方式解决,同时代码经得起推敲和扩展,才是最主要的。

还是那句话,你可以不用,但不能不会。

💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

《程序猿之设计模式实战 · 观察者模式》-LMLPHP

09-17 08:46