文章目录
观察者模式 (Observer Pattern)
观察者模式 是一种 行为型设计模式 ,用于定义对象间的一种 一对多 依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。
原理
- 核心思想 :
- 当目标对象(Subject)发生变化时,通知所有观察者(Observer)。
- 将目标与观察者之间的依赖关系分离,使得两者可以独立变化。
- 适用场景 :
- 一个对象的变化需要通知其他对象。
- 不希望目标对象和观察者之间存在紧耦合关系。
- 参与角色 :
- Subject(目标/被观察者) :
- 保存观察者对象的列表。
- 提供注册、移除观察者的方法。
- 当状态发生改变时,通知所有观察者。
- Observer(观察者) :
- 提供更新接口,供目标调用。
- ConcreteSubject(具体目标) :
- 实现具体的状态逻辑。
- ConcreteObserver(具体观察者) :
- 实现更新接口,定义具体更新行为。
- Subject(目标/被观察者) :
优点
- 解耦:观察者和目标分离,可以独立扩展。
- 动态响应:目标状态变化时,观察者可以动态收到通知。
- 复用性强:观察者模式非常灵活,适用于各种场景。
缺点
- 通知机制复杂性:通知过程可能产生较高的时间开销。
- 可能出现循环依赖:当观察者也会触发目标变化时,需防止死循环。
- 难以控制通知顺序:观察者的调用顺序由实现决定。
示例代码
场景描述
以新闻发布系统为例,新闻发布者是目标,订阅用户是观察者。当新闻发布时,所有订阅用户都会收到通知。
1. 定义观察者接口
java
// 观察者接口
public interface Observer {
void update(String message); // 接收目标的更新通知
}
2. 定义目标接口
java
// 目标接口
public interface Subject {
void registerObserver(Observer observer); // 注册观察者
void removeObserver(Observer observer); // 移除观察者
void notifyObservers(); // 通知所有观察者
}
3. 实现具体目标类
java
import java.util.ArrayList;
import java.util.List;
// 具体目标类
public class NewsPublisher implements Subject {
private List<Observer> observers; // 保存观察者列表
private String news; // 新闻内容
public NewsPublisher() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(news); // 通知每个观察者
}
}
// 更新新闻并通知观察者
public void setNews(String news) {
this.news = news;
notifyObservers();
}
}
4. 实现具体观察者类
java
// 具体观察者
public class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received news: " + message);
}
}
5. 客户端代码
java
public class ObserverPatternExample {
public static void main(String[] args) {
NewsPublisher publisher = new NewsPublisher();
// 创建观察者
Observer alice = new Subscriber("Alice");
Observer bob = new Subscriber("Bob");
Observer charlie = new Subscriber("Charlie");
// 注册观察者
publisher.registerObserver(alice);
publisher.registerObserver(bob);
// 发布新闻
publisher.setNews("Breaking News: Observer Pattern Explained!");
// 移除观察者
publisher.removeObserver(alice);
// 再次发布新闻
publisher.setNews("Update: Observer Pattern is Easy!");
}
}
输出结果
text
Alice received news: Breaking News: Observer Pattern Explained!
Bob received news: Breaking News: Observer Pattern Explained!
Bob received news: Update: Observer Pattern is Easy!
UML 类图
+------------------+
| Subject |<-------------------+
+------------------+ |
| + registerObserver()| |
| + removeObserver() | |
| + notifyObservers() | |
+------------------+ |
^ |
| |
+-----------------------+ +-----------------------+
| NewsPublisher | | Observer |
+-----------------------+ +-----------------------+
| - observers : List | | + update(message) |
| + setNews(news) | +-----------------------+
| + notifyObservers() | ^
+-----------------------+ |
| |
+-----------------------+ +-----------------------+
| Subscriber | | Subscriber |
+-----------------------+ +-----------------------+
| - name : String | | - name : String |
| + update(message) | | + update(message) |
+-----------------------+ +-----------------------+
使用场景
- 事件监听:GUI 开发中,按钮点击事件的监听。
- 消息订阅:发布/订阅模式,如 RabbitMQ、Kafka。
- 实时更新:如股票价格、天气更新。
优化与扩展
- 使用 Java 内置类 :
- Java 提供了
Observable
类和Observer
接口。 - 但
Observable
已被标记为过时,推荐自定义实现。
- Java 提供了
- 多线程支持 :
- 使用线程安全的集合
CopyOnWriteArrayList
避免并发问题。
- 使用线程安全的集合
- 结合其他模式 :
- 与 中介者模式 结合,简化复杂的观察者关系。
小结
- 观察者模式在事件驱动系统中非常常用。
- 它解耦了目标和观察者,但需要注意性能问题。
- 可结合其他模式(如工厂模式)简化观察者的管理和创建。