一、观察者模式定义
观察者模式(Observer Pattern)也叫做发布订阅模式(Publish/subscribe),它是一个在项目中经常使用的模式,它是一种行为型设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。其定义如下:
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。(Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.)
观察者模式通用类图如下
观察者模式中的几种角色:
Subject被观察者:定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。
Observer观察者:观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。
ConcreteSubject具体的被观察者:定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
ConcreteObserver具体的观察者:每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。
其实个人来说,我觉得“发布订阅模式”要比“观察者模式”的叫法更贴合它的意思,比如观察者模式在现实世界中的例子:报纸订阅,如果你订阅了一份杂志或报纸, 那就不需要再去报摊查询新出版的刊物了。 出版社 (即应用中的 “发布者”) 会在刊物出版后 (甚至提前) 直接将最新一期寄送至你的邮箱中。我们称这个过程叫做“订阅”,而非“观察”,所以我觉得应该叫“发布订阅模式”。
二、观察者模式案例
下面以新闻订阅为例实现观察者模式:假设我们有一个新闻发布者(主题),它可以添加和删除订阅者(观察者),并在发布新闻时通知所有订阅者。订阅者可以是各种类型的用户,比如网站访问者、移动应用用户等。
设计类图如下
主题接口
public interface NewsPublisher {
void registerSubscriber(NewsSubscriber subscriber);
void removeSubscriber(NewsSubscriber subscriber);
void notifySubscribers(String news);
}
观察者接口
public interface NewsSubscriber {
void update(String news);
}
主题实现接口
public class NewspaperPublisher implements NewsPublisher {
private List<NewsSubscriber> subscribers = new ArrayList<>();
@Override
public void registerSubscriber(NewsSubscriber subscriber) {
subscribers.add(subscriber);
}
@Override
public void removeSubscriber(NewsSubscriber subscriber) {
subscribers.remove(subscriber);
}
@Override
public void notifySubscribers(String news) {
for (NewsSubscriber subscriber : subscribers) {
subscriber.update(news);
}
}
public void publishNews(String news) {
notifySubscribers(news);
}
}
观察者具体实现接口
//PC端
public class WebsiteSubscriber implements NewsSubscriber {
private String name;
public WebsiteSubscriber(String name) {
this.name = name;
}
@Override
public void update(String news) {
System.out.println("Website subscriber " + name + " received news: " + news);
}
}
//移动端
public class MobileAppSubscriber implements NewsSubscriber {
private String name;
public MobileAppSubscriber(String name) {
this.name = name;
}
@Override
public void update(String news) {
System.out.println("Mobile app subscriber " + name + " received news: " + news);
}
}
三、JDK内置的观察者模式实现
JDK已经有内置的观察者模式的实现方式。这个实现方式就是使用了 java.util.Observable
类和 java.util.Observer
接口。
java.util.Observable:可观察的主题类,该类不是抽象类,继承它可方便的集成主题类相关的功能:管理观察者以及通知观察者。
java.util.Observer:观察者接口类,和Observable类搭配使用,实现该接口可接收主题类发送的通知消息。
还是上面的案例,改成使用JDK内置的两个工具类
可观察的主题类
public class NewsPublisher extends Observable {
private String news;
public void publishNews(String news) {
this.news = news;
setChanged();
notifyObservers(news);
}
}
观察者类
public class NewsSubscriber implements Observer {
private String name;
public NewsSubscriber(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(name + " received news: " + arg);
}
}
测试类
public class JDKObserverPatternExample {
public static void main(String[] args) {
NewsPublisher publisher = new NewsPublisher();
NewsSubscriber subscriber1 = new NewsSubscriber("Subscriber 1");
NewsSubscriber subscriber2 = new NewsSubscriber("Subscriber 2");
publisher.addObserver(subscriber1);
publisher.addObserver(subscriber2);
publisher.publishNews("Breaking news: A new product launched!");
}
}
在上面的示例中,NewsPublisher
是一个可观察的主题类,它继承了 Observable
类。NewsSubscriber
是观察者类,它实现了 Observer
接口。在 JDKObserverPatternExample
类中,我们创建了一个 NewsPublisher
对象,并向其添加了两个观察者对象。当新闻发布者发布新闻时,所有的观察者都会收到通知并作出相应的响应。
四、Spring框架源码中的观察者模式
1、使用案例
Spring 框架中的观察者模式主要体现在事件驱动编程方面。Spring 通过事件驱动机制来实现模块之间的解耦,允许一个模块(发布者)在状态改变时通知其他模块(订阅者)。
首先先看下怎么用
定义事件类,需要继承ApplicationEvent
类
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent {
private static final long serialVersionUID = -1L;
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
定义发布者
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class EventPublisher {
private final AnnotationConfigApplicationContext context;
public EventPublisher(AnnotationConfigApplicationContext context) {
this.context = context;
}
public void publishCustomEvent(String messaga) {
context.publishEvent(new CustomEvent(this, messaga));
}
}
定义监听者
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("Received custom event: " + event.getMessage());
}
}
启动类
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(CustomEventListener.class);
context.register(EventPublisher.class);
context.refresh();
EventPublisher publisher = context.getBean(EventPublisher.class);
publisher.publishCustomEvent("Hello,Spring Events !");
}
}
运行结果
Received custom event: Hello,Spring Events !
如果我再添加一个监听者
@Component
public class CustomEventListener1 implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("Received custom event1: " + event.getMessage());
}
}
那运行结果就变成了
Received custom event: Hello,Spring Events !
Received custom event1: Hello,Spring Events !
2、源码解析
入口在org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)
方法,debug进入该方法,最终可以看到如下代码
查找所有该类型Event的监听者,并for循环挨个执行invokeListener方法:
实际上执行的就是onApplicationEvent方法,实现了监听者回调。
END.
注意:本文归作者所有,未经作者允许,不得转载