一、定义
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当该主题对象状态发生变化时,会自动通知所有依赖它的观察者对象,实现状态同步。
通俗理解:一个对象变化,通知一群人。
二、适用场景
观察者模式适用于以下场景:
- 对象之间存在一对多关系,一个对象状态变化需要通知多个对象;
- 需要建立一种动态联动机制,解耦事件发生者与事件处理者;
- 需要实现事件驱动(如发布订阅模型、广播通知);
- 常用于消息队列、UI事件、系统监控、缓存刷新、数据库变更通知等场景。
三、核心角色(Participants)
角色 | 说明 |
Subject(被观察者) | 主题对象,管理观察者对象,状态变更时通知观察者 |
Observer(观察者) | 接收通知的对象,定义接收通知的接口 |
ConcreteSubject | 具体被观察者,含有状态,并在状态改变时通知所有观察者 |
ConcreteObserver | 具体观察者,实现响应通知的逻辑 |
四、UML 类图(UML Diagram)
+--------------------+
| Subject |<------------------+
|--------------------| |
| + attach() | |
| + detach() | |
| + notifyObservers()| |
+--------------------+ |
▲ |
| |
+------------------------+ +----------------------+
| ConcreteSubject | | Observer |
| + getState() | | + update() |
| + setState() | +----------------------+
| + notifyObservers() | ▲
+------------------------+ |
|
+--------------------------+
| ConcreteObserver |
| + update() |
+--------------------------+
五、真实业务场景示例
场景说明:
假设一个微信公众号平台,用户可以订阅公众号,当公众号发布新消息时,所有订阅用户都会收到通知。
1. 观察者接口(Observer 角色)
// Observer:观察者接口,定义接收通知的统一方法
public interface Subscriber {
void update(String message);
}
2. 具体观察者类(ConcreteObserver 角色)
// ConcreteObserver:具体观察者,实现接收通知逻辑
public class User implements Subscriber {
private String name;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println("用户 " + name + " 收到推送消息:" + message);
}
}
3. 被观察者接口(Subject 角色)
// Subject:被观察者接口,定义添加/删除/通知观察者的方法
public interface WeChatOfficialAccount {
void subscribe(Subscriber subscriber);
void unsubscribe(Subscriber subscriber);
void publish(String message);
}
4. 具体被观察者类(ConcreteSubject 角色)
// ConcreteSubject:具体被观察者,管理订阅者并发送消息
import java.util.ArrayList;
import java.util.List;
public class TechPublicAccount implements WeChatOfficialAccount {
private List<Subscriber> subscribers = new ArrayList<>();
@Override
public void subscribe(Subscriber subscriber) {
subscribers.add(subscriber);
}
@Override
public void unsubscribe(Subscriber subscriber) {
subscribers.remove(subscriber);
}
@Override
public void publish(String message) {
System.out.println("公众号推送消息:" + message);
for (Subscriber subscriber : subscribers) {
subscriber.update(message);
}
}
}
5. 客户端代码(Client)
public class ObserverTest {
public static void main(String[] args) {
// 被观察者
TechPublicAccount techAccount = new TechPublicAccount();
// 观察者
Subscriber user1 = new User("张三");
Subscriber user2 = new User("李四");
Subscriber user3 = new User("王五");
// 添加订阅者
techAccount.subscribe(user1);
techAccount.subscribe(user2);
techAccount.subscribe(user3);
// 发布一条推文
techAccount.publish("Java 观察者模式详解已上线!");
// Bob 取消订阅
techAccount.unsubscribe(user2);
// 再次发布
techAccount.publish("Spring Boot 教程第二期上线!");
}
}
💡 类与角色对照表
类名 | 设计模式角色 | 说明 |
| Observer | 抽象观察者,定义 update() 方法 |
| ConcreteObserver | 具体观察者,实现 update() 通知 |
| Subject | 抽象主题,定义订阅/取消/通知 |
| ConcreteSubject | 具体主题,实现发布并通知用户 |
| Client | 客户端,组装对象并触发业务流程 |
六、优缺点分析(Pros & Cons)
✅ 优点
- 低耦合:被观察者与观察者解耦,便于模块独立开发和维护;
- 支持广播通信:一个状态变更可通知多个观察者;
- 符合开闭原则:新增观察者时无需修改原有代码;
- 高扩展性:动态添加/删除订阅者,适应变化灵活。
❌ 缺点
- 可能引发性能问题:观察者数量多时,通知开销变大;
- 通知顺序不确定:可能导致观察者状态不一致;
- 被动更新风险:观察者无法阻止消息、不关心也会被通知;
- 调试难度上升:涉及多个对象协作,调试成本略高。
七、观察者模式常见应用
- GUI 组件事件监听(按钮点击、输入框变动等)
- 消息总线(如 EventBus、MQ 监听器)
- 发布-订阅系统(微信通知、邮件推送)
- 数据模型更新通知(MVC 中 Model 通知 View)
- 缓存更新通知机制
八、总结(Summary)
观察者模式是一种非常经典的行为型设计模式,适用于多个对象依赖某个对象状态的变化,并自动同步状态的场景。通过它,我们可以实现模块之间的解耦、事件的异步通知、系统的灵活扩展。