什么是观察者

观察者模式的主要角色包括:

  • 主题(Subject): 也称为被观察者或可观察对象。它维护了一系列观察者对象,并提供方法用于注册、删除和通知观察者。当主题的状态发生改变时,它会通知所有注册的观察者。

  • 观察者(Observer): 观察主题的对象。观察者定义了一个更新方法,主题在状态改变时会调用这个方法来通知观察者。观察者可以根据主题的通知来执行相应的操作。

观察者的应用

观察者模式在实际应用中经常用于处理事件驱动的编程场景,如图形用户界面(GUI)开发、消息传递系统等。通过观察者模式,可以实现对象之间的解耦,提高系统的灵活性和可维护性。
Spring Framework中,观察者模式的应用非常广泛,尤其在Spring的事件驱动机制中。Spring的事件机制允许对象在特定事件发生时发布事件,并允许其他对象注册为监听器以接收这些事件。这与观察者模式的概念非常相似,其中事件源就是观察者模式中的主题,而事件监听器就是观察者。

应用程序事件: Spring允许应用程序发布自定义事件,并提供了ApplicationEvent和ApplicationListener接口。应用程序可以创建自定义事件类,并在需要时发布这些事件。其他对象可以实现ApplicationListener接口并注册为监听器,以接收并处理这些事件。

Spring MVC事件: 在Spring MVC中,可以使用 ApplicationEventPublisher 接口发布自定义事件,并通过@EventListener注解或实现 ApplicationListener 接口的方式来处理这些事件。这使得在MVC架构中进行解耦和处理事件变得更加容易。

如何实现

日常中比较经典的实例场景 , 举个例子,如博客园的文章订阅, 当关注的作者发布了新的文章后,关注其的粉丝就会收到消息通知,这里将代码拆出来如下。

import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String news);
}

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

// 新闻发布者
class NewsPublisher implements Subject {
    private List<Observer> observers = new ArrayList<>();

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

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

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

    public void publishNews(String news) {
        System.out.println("发布新闻: " + news);
        notifyObservers(news);
    }
}

// 观察者 - 读者
class Reader implements Observer {
    private String name;

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

    @Override
    public void update(String news) {
        System.out.println(name + " 收到新闻: " + news);
    }
}

public class ObserverPatternExample {
        // 创建新闻发布者
        NewsPublisher publisher = new NewsPublisher();

        // 创建两个观察者(读者)
        Observer reader1 = new Reader("小明");
        Observer reader2 = new Reader("小红");

        // 注册观察者
        publisher.registerObserver(reader1);
        publisher.registerObserver(reader2);

        // 发布新闻
        publisher.publishNews("Java 21发布了!");
        publisher.publishNews("Spring Framework 更新了!");

        // 读者取消订阅
        publisher.removeObserver(reader2);

        // 再次发布新闻
        publisher.publishNews("小米 su7 上线了,雷总为你开车门,快行动起来吧!");
    }
}

程序运行日志如下

发布新闻: Java 21发布了!
小明 收到新闻: Java 21发布了!
小红 收到新闻: Java 21发布了!
发布新闻: Spring Framework 更新了!
小明 收到新闻: Spring Framework 更新了!
小红 收到新闻: Spring Framework 更新了!
发布新闻: 小米 su7 上线了,雷总为你开车门,快行动起来吧!
小明 收到新闻: 小米 su7 上线了,雷总为你开车门,快行动起来吧!

结语

这里介绍观察者,是希望从易于理解的概念开始对 Reactive Programing 的理解,在响应式编程中多数基于观察者模式思想演变而来,如在 Reactor 中,订阅者(Subscriber)订阅了数据流(Publisher),并在数据流中的元素发生变化时接收通知。

通知机制: 在观察者模式中,主题状态的变化会触发通知,通知会被发送给所有注册的观察者。在Reactor中,数据流中的元素发生变化时会触发通知,通知会被发送给所有订阅了该数据流的订阅者。

事件驱动编程: 观察者模式和 Reactor 都支持事件驱动的编程模型。在观察者模式中,事件源(主题)发生事件(状态变化),并通知观察者。在 Reactor 中,事件(数据元素)在流中传递,并且订阅者可以对这些事件进行响应式地处理。