跳到主要内容

观察者模式

介绍

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,所有依赖于它的观察者都会得到通知并自动更新。

原理

观察者模式的核心原理包括:

  1. 主题(Subject):维护一组观察者,并提供添加和删除观察者的方法,以及通知所有观察者的方法
  2. 观察者(Observer):定义一个更新接口,当主题状态发生变化时被调用
  3. 具体主题(ConcreteSubject):实现主题接口,当状态发生变化时通知所有观察者
  4. 具体观察者(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");
}
}

解决方案

应用场景

  1. 事件处理系统:如GUI中的按钮点击事件
  2. 消息通知系统:如邮件通知、短信通知
  3. 数据同步:多个视图依赖于同一数据模型
  4. 监控系统:监控某个对象的状态变化
  5. 发布-订阅模式:消息队列中的发布-订阅机制

最佳实践

  1. 避免循环依赖:观察者和主题之间不应形成循环依赖
  2. 考虑线程安全:在多线程环境中,确保对观察者列表的操作是线程安全的
  3. 提供取消注册机制:如detach方法,避免内存泄漏
  4. 区分推模型和拉模型
    • 推模型:主题向观察者推送所有信息
    • 拉模型:观察者主动从主题获取所需信息
  5. 使用弱引用:在观察者数量庞大时,避免内存泄漏

优缺点

优点

  • 实现松耦合
  • 支持广播通信
  • 符合开闭原则
  • 可以动态添加和删除观察者

缺点

  • 如果观察者数量过多,通知可能会很慢
  • 可能导致循环引用
  • 观察者无法知道主题是如何变化的,只能知道变化的结果

工具推荐

  1. Java内置API:java.util.Observable和java.util.Observer
  2. RxJava/RxAndroid:响应式编程库,基于观察者模式
  3. Project Reactor:响应式编程库,提供丰富的观察者模式实现
  4. Spring Framework:提供ApplicationEvent和ApplicationListener接口
  5. Google Guava:提供EventBus实现发布-订阅模式