0%

观察者模式

观察者模式(Observer Pattern):对象间的联动通知机制

观察者模式是行为型设计模式的一种,核心思想是定义对象间的一对多依赖关系:当一个对象(目标)的状态发生改变时,所有依赖它的对象(观察者)会自动收到通知并更新。这种模式就像 “订阅 - 发布” 系统 —— 订阅者(观察者)关注发布者(目标),当发布者有新内容时,所有订阅者都会收到推送,核心是 “状态联动,自动更新”。

观察者模式的核心结构

观察者模式通过四个核心角色实现对象间的联动,分工明确且耦合度低:

目标接口 / 类(Subject)

  • 定义被观察对象的接口,提供注册、移除观察者及通知所有观察者的方法。
  • 示例:NewsPublisher(新闻发布者,定义addSubscriber()removeSubscriber()notifySubscribers())。

具体目标(ConcreteSubject)

  • 实现目标接口,维护自身状态,当状态改变时调用notify()方法通知所有观察者。
  • 示例:TechNewsPublisher(科技新闻发布者,状态为最新新闻内容)。

观察者接口(Observer)

  • 定义观察者的接口,声明接收通知并更新自身的方法(通常名为update())。
  • 示例:Subscriber(订阅者,定义update(String news)方法)。

具体观察者(ConcreteObserver)

  • 实现观察者接口,在收到通知时执行具体的更新逻辑,通常会保存对目标的引用以获取最新状态。
  • 示例:EmailSubscriber(邮件订阅者,收到新闻后发送邮件)、AppSubscriber(APP 订阅者,收到新闻后推送通知)。

代码实现示例

以 “新闻订阅系统” 为例,展示观察者模式的实现:新闻发布者(目标)发布新闻时,所有订阅者(观察者)会自动收到通知。

1. 目标接口与具体目标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 1. 目标接口:新闻发布者
public interface NewsPublisher {
// 注册观察者(订阅)
void addSubscriber(Subscriber subscriber);
// 移除观察者(取消订阅)
void removeSubscriber(Subscriber subscriber);
// 通知所有观察者(发布新闻)
void notifySubscribers();
}

// 2. 具体目标:科技新闻发布者
public class TechNewsPublisher implements NewsPublisher {
private List<Subscriber> subscribers = new ArrayList<>(); // 观察者列表
private String latestNews; // 目标状态:最新新闻

// 设置新闻内容(状态改变)
public void setNews(String news) {
this.latestNews = news;
notifySubscribers(); // 状态改变后通知所有观察者
}

// 获取最新新闻(供观察者调用)
public String getLatestNews() {
return latestNews;
}

@Override
public void addSubscriber(Subscriber subscriber) {
subscribers.add(subscriber);
}

@Override
public void removeSubscriber(Subscriber subscriber) {
subscribers.remove(subscriber);
}

@Override
public void notifySubscribers() {
// 遍历所有观察者,触发更新
for (Subscriber subscriber : subscribers) {
subscriber.update();
}
}
}

2. 观察者接口与具体观察者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 3. 观察者接口:订阅者
public interface Subscriber {
// 接收通知并更新
void update();
}

// 4. 具体观察者1:邮件订阅者
public class EmailSubscriber implements Subscriber {
private NewsPublisher publisher; // 引用目标以获取最新状态

public EmailSubscriber(NewsPublisher publisher) {
this.publisher = publisher;
}

@Override
public void update() {
// 从目标获取最新状态并处理
String news = ((TechNewsPublisher) publisher).getLatestNews();
System.out.println("邮件订阅者收到新闻:" + news);
}
}

// 5. 具体观察者2:APP订阅者
public class AppSubscriber implements Subscriber {
private NewsPublisher publisher;

public AppSubscriber(NewsPublisher publisher) {
this.publisher = publisher;
}

@Override
public void update() {
String news = ((TechNewsPublisher) publisher).getLatestNews();
System.out.println("APP订阅者收到新闻:" + news);
}
}

3. 客户端使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ObserverDemo {
public static void main(String[] args) {
// 创建目标(新闻发布者)
TechNewsPublisher publisher = new TechNewsPublisher();

// 创建观察者(订阅者)并注册
Subscriber emailSub = new EmailSubscriber(publisher);
Subscriber appSub = new AppSubscriber(publisher);
publisher.addSubscriber(emailSub);
publisher.addSubscriber(appSub);

// 发布新闻(状态改变,自动通知观察者)
publisher.setNews("Java 21正式发布!");
// 输出:
// 邮件订阅者收到新闻:Java 21正式发布!
// APP订阅者收到新闻:Java 21正式发布!

// 移除一个观察者(取消订阅)
publisher.removeSubscriber(appSub);
System.out.println("\n移除APP订阅者后:");
publisher.setNews("Spring Framework 6.1.0发布");
// 输出:
// 邮件订阅者收到新闻:Spring Framework 6.1.0发布
}
}

观察者模式的核心优势

  1. 松耦合的联动关系
    目标与观察者之间通过接口通信,互不依赖具体实现:
    • 目标无需知道观察者的具体类型,只需调用其update()方法。
    • 观察者可随时新增或移除,不影响目标的逻辑。
  2. 自动通知与更新
    目标状态改变时,所有观察者会被自动通知并更新,无需手动触发,确保状态一致性。
  3. 支持一对多通信
    一个目标可对应多个观察者(如新闻发布者可被无数用户订阅),适合广播场景。
  4. 符合开闭原则
    新增观察者时无需修改目标代码,只需实现观察者接口并注册,扩展性强。

适用场景

  1. 状态联动场景
    当一个对象的状态变化需要联动更新其他多个对象时(如:
    • GUI 界面:按钮点击后,多个组件(文本框、列表)联动更新。
    • 股票系统:股价变动时,所有关注该股票的用户收到提醒。
    • 事件监听:如鼠标点击、键盘输入等事件的处理。
  2. 订阅 - 发布系统
    如 RSS 订阅、邮件列表、消息队列(MQ)的发布 - 订阅模式(本质是观察者模式的扩展)。
  3. 事件驱动架构
    系统核心模块作为目标,其他模块作为观察者监听核心事件(如日志系统、监控系统)。

优缺点分析

优点

  • 低耦合:目标与观察者通过接口交互,减少直接依赖。
  • 高灵活性:观察者可动态添加 / 移除,适应变化。
  • 自动化:状态变化时自动通知,减少手动协调成本。

缺点

  • 通知顺序不确定:目标对观察者的通知顺序不保证,若观察者间有依赖关系可能导致问题。
  • 资源消耗:若观察者过多或更新逻辑复杂,可能导致通知效率降低。
  • 循环依赖风险:若观察者更新时又触发目标状态改变,可能导致无限循环。

经典应用案例

  1. Java 的java.util.ObservableObserver
    Java 内置了观察者模式的实现:Observable是目标类,Observer是观察者接口,通过notifyObservers()触发更新。(注:Java 9 后已标记为过时,推荐使用java.beans包或第三方库)。
  2. Spring 的事件机制
    Spring 的ApplicationEvent(事件,类似目标状态)和ApplicationListener(监听器,类似观察者)实现了观察者模式,用于组件间的解耦通信(如ContextRefreshedEvent通知容器刷新完成)。
  3. GUI 框架的事件监听
    如 Swing 的ActionListener(按钮点击事件的观察者)、MouseListener(鼠标事件的观察者),按钮作为目标,点击时通知所有监听器。
  4. 消息队列(MQ)的发布 - 订阅模式
    如 RabbitMQ 的fanout交换机,生产者(目标)发送消息后,所有绑定该交换机的队列(观察者)都会收到消息,是分布式系统中的观察者模式扩展。

总结

观察者模式通过 “目标 - 观察者” 的一对多关系,实现了对象间的低耦合联动,核心是 “状态变化自动通知,观察者被动更新”。它特别适合需要联动更新的场景,如事件驱动、订阅系统等。使用时需注意控制观察者数量和更新逻辑复杂度,避免效率问题

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10