观察者模式
介绍
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,所有依赖于它的观察者都会得到通知并自动更新。
原理
观察者模式的核心原理包括:
- 主题(Subject):维护一组观察者,并提供添加和删除观察者的方法,以及通知所有观察者的方法
- 观察者(Observer):定义一个更新接口,当主题状态发生变化时被调用
- 具体主题(ConcreteSubject):实现主题接口,当状态发生变化时通知所有观察者
- 具体观察者(ConcreteObserver):实现观察者接口,保存对具体主题的引用,当收到主题的通知时更新自己
图示
+----------------+ +----------------+
| Observer | | Subject |
+----------------+ +----------------+
| + update() |<-------| + attach() |
+-------^--------+ | + detach() |
| | + notify() |
+-------+--------+ +-------^--------+
| ConcreteObserver| |
+----------------+ |
| - subject | |
| + update() | |
+----------------+ +-----+------+
| ConcreteSubject |
+----------------+
| - observers[] |
| + attach() |
| + detach() |
| + notify() |
| + setState() |
| + getState() |
+----------------+
代码示例
观察者接口
public interface Observer {
void update();
}
主题接口
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
具体主题
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String state;
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
public void setState(String state) {
this.state = state;
notifyObservers();
}
public String getState() {
return state;
}
}
具体观察者
public class ConcreteObserver implements Observer {
private String name;
private ConcreteSubject subject;
public ConcreteObserver(String name, ConcreteSubject subject) {
this.name = name;
this.subject = subject;
}
@Override
public void update() {
String state = subject.getState();
System.out.println(name + " 收到通知: 状态变为 " + state);
}
}
客户端代码
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("观察者1", subject);
Observer observer2 = new ConcreteObserver("观察者2", subject);
subject.attach(observer1);
subject.attach(observer2);
subject.setState("状态1");
System.out.println();
subject.detach(observer1);
subject.setState("状态2");
}
}
解决方案
应用场景
- 事件处理系统:如GUI中的按钮点击事件
- 消息通知系统:如邮件通知、短信通知
- 数据同步:多个视图依赖于同一数据模型
- 监控系统:监控某个对象的状态变化
- 发布-订阅模式:消息队列中的发布-订阅机制
最佳实践
- 避免循环依赖:观察者和主题之间不应形成循环依赖
- 考虑线程安全:在多线程环境中,确保对观察者列表的操作是线程安全的
- 提供取消注册机制:如detach方法,避免内存泄漏
- 区分推模型和拉模型:
- 推模型:主题向观察者推送所有信息
- 拉模型:观察者主动从主题获取所需信息
- 使用弱引用:在观察者数量庞大时,避免内存泄漏
优缺点
优点:
- 实现松耦合
- 支持广播通信
- 符合开闭原则
- 可以动态添加和删除观察者
缺点:
- 如果观察者数量过多,通知可能会很慢
- 可能导致循环引用
- 观察者无法知道主题是如何变化的,只能知道变化的结果
工具推荐
- Java内置API:java.util.Observable和java.util.Observer
- RxJava/RxAndroid:响应式编程库,基于观察者模式
- Project Reactor:响应式编程库,提供丰富的观察者模式实现
- Spring Framework:提供ApplicationEvent和ApplicationListener接口
- Google Guava:提供EventBus实现发布-订阅模式