观察者模式
1/27/24About 5 min
观察者模式为组件向相关接收方广播消息提供了灵活的方法。该模式定义了对象间一到多的依赖关系,这样当对象改变状态时,将自动通知并更新它所有的依赖对象。

观察者模式角色:
- 抽象主题(Subject):也称为抽象目标类。这个角色定义了观察者和被观察者之间的接口,它通常包含以下方法:
addObserver(Observer observer):添加一个观察者到订阅列表中。 removeObserver(Observer observer):从订阅列表中移除一个观察者。 notifyObservers() 或 notifyObservers(Datatype update):通知所有已注册的观察者对象更新状态,有时候会携带更新的数据。 2. 具体主题(ConcreteSubject):实现了抽象主题的类,它在内部状态改变时负责通知所有已注册的观察者。 3. 抽象观察者(Observer):定义了一个接口,该接口使得观察者可以了解主题对象的任何状态变化,并提供相应的方法来更新自己。通常包含: update() 方法,当主题对象的状态发生改变时调用此方法来更新观察者的状态。 4. 具体观察者(ConcreteObserver):实现了抽象观察者接口的类,存储对主题对象的引用并实现具体的更新逻辑,在接收到主题的通知后更新自身的状态。
代码实现
抽象主题
抽象主题中,管理所有要通知的观察者集合,并提供notifyObservers方法进行遍历通知。
public abstract class Subject {
private final List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
protected void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}具体主题
具体主题需要在自身状态发生变化的时候,通知观察者。
public class ConcreteSubject extends Subject {
private String message;
public void setMessage(String message) {
this.message = message;
notifyObservers(message);
}
public String getMessage() {
return message;
}
}抽象观察者
public interface Observer {
void update(String message);
}具体观察者
public class ConcreteObserver implements Observer {
@Override
public void update(String message) {
System.out.printf("%s: [%s]%n", this.getClass().getName(), message);
}
}使用
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver concreteObserver = new ConcreteObserver();
subject.addObserver(concreteObserver);
subject.setMessage("new messages");
}
}结果:

观察者模式与其他模式的对比
| 模式 | 功能 | 实现方式 | 适用场景 |
|---|---|---|---|
| 观察者模式 | 一对多依赖通知 | 主题维护观察者列表,状态变化时通知所有观察者 | 一个对象状态变化需要影响多个其他对象时 |
| 发布-订阅模式 | 消息发布与订阅 | 通过消息队列或事件总线解耦发布者和订阅者 | 发布者和订阅者需要完全解耦时 |
| 中介者模式 | 减少对象间直接耦合 | 通过中介者统一管理对象间通信 | 对象间存在复杂网状依赖关系时 |
| 责任链模式 | 避免请求发送者与接收者耦合 | 请求沿责任链传递,直到被处理 | 需要动态决定请求处理者时 |
总结
核心思想
观察者模式的核心思想是定义对象间的一对多依赖关系,当一个对象(主题)的状态发生变化时,所有依赖它的对象(观察者)都会自动收到通知并更新。这种模式实现了主题和观察者之间的松散耦合,使得它们可以独立地变化。
主要角色
- 抽象主题(Subject):定义了管理观察者的接口,包括添加、移除和通知观察者的方法
- 具体主题(ConcreteSubject):实现抽象主题,维护内部状态,当状态变化时通知所有观察者
- 抽象观察者(Observer):定义了接收通知并更新的接口
- 具体观察者(ConcreteObserver):实现抽象观察者,存储对主题的引用,接收通知后执行更新逻辑
实现方式
- 定义抽象主题接口,包含管理观察者的方法
- 实现具体主题类,维护观察者列表和内部状态
- 定义抽象观察者接口,包含更新方法
- 实现具体观察者类,重写更新方法
- 客户端创建主题和观察者对象,注册观察者到主题
优缺点
优点:
- 实现了主题和观察者之间的松散耦合
- 主题和观察者可以独立地扩展和变化
- 支持广播通信,一个主题可以通知多个观察者
- 符合开闭原则,添加新的观察者不需要修改主题代码
- 提高了系统的灵活性和可维护性
缺点:
- 如果观察者数量过多,通知可能会导致性能问题
- 如果主题和观察者之间存在循环依赖,可能导致系统崩溃
- 观察者无法知道主题状态变化的具体原因
- 通知顺序可能影响系统行为,且通常不可控
适用场景
- 一个对象的状态变化需要影响多个其他对象
- 系统需要实现广播通信
- 主题和观察者之间需要松耦合
- 需要动态添加或移除观察者
- 事件驱动系统、消息订阅系统、GUI组件交互等场景
实际应用
- GUI事件处理:按钮点击、文本输入等事件触发UI更新
- 消息订阅系统:发布者发布消息,订阅者接收并处理
- Spring事件机制:ApplicationEvent和ApplicationListener的实现
- JavaScript事件处理:DOM事件模型中的事件监听
- 分布式系统中的事件通知:微服务间的事件驱动通信
- 股票行情系统:股票价格变化时通知所有关注的投资者