观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都会自动收到通知并更新。
核心概念
观察者模式包含以下核心角色:
-
Subject(主题/被观察者)
- 维护观察者列表
- 提供注册、删除和通知观察者的接口
-
ConcreteSubject(具体主题)
- 实现Subject接口
- 管理自身状态,并在状态变化时通知所有观察者
-
Observer(观察者)
- 定义更新接口,接收主题通知
-
ConcreteObserver(具体观察者)
- 实现Observer接口
- 根据主题的状态变化执行具体操作
模式特点
- 松耦合:主题和观察者之间松耦合
- 自动通知:状态变化时自动通知观察者
- 一对多:一个主题可对应多个观察者
- 动态订阅:可动态添加/删除观察者
应用场景
观察者模式适用于以下场景:
- 消息发布/订阅系统:如聊天室、新闻推送
- 用户界面组件:GUI事件处理
- 实时数据监控:如股票价格变动、温度监控
- 事件驱动系统:如游戏引擎、企业监控系统
- 分布式系统:节点状态变更通知
代码实现示例
以下是观察者模式的基本实现(推模型):
// 观察者接口
public interface Observer {void update(String message);
}// 主题接口
public interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}// 具体主题 - 新闻发布中心
public class NewsAgency implements Subject {private List<Observer> observers = new ArrayList<>();private String news;public void setNews(String news) {this.news = news;notifyObservers();}public void registerObserver(Observer o) {observers.add(o);}public void removeObserver(Observer o) {observers.remove(o);}public void notifyObservers() {for (Observer o : observers) {o.update(news);}}
}// 具体观察者 - 新闻订阅者
public class NewsSubscriber implements Observer {private String name;public NewsSubscriber(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " 收到新闻: " + message);}
}
通知模型对比
观察者模式有两种主要的通知模型:
模型类型 | 数据传递方式 | 优点 | 缺点 |
---|---|---|---|
推模型 | 主题主动推送详细数据给观察者 | 实时性强,响应快 | 可能传递冗余数据 |
拉模型 | 观察者收到通知后主动拉取数据 | 按需获取,灵活性高 | 增加主题的访问压力 |
Java内置支持
Java在java.util
包中提供了观察者模式的实现:
Observable
类(主题)Observer
接口
但自Java 9起已被标记为@Deprecated
,推荐使用java.beans
包中的PropertyChangeListener
和PropertyChangeSupport
。
优缺点分析
优点:
- 主题和观察者之间松耦合
- 支持广播通信
- 符合开放-封闭原则
- 可动态添加/删除观察者
缺点:
- 通知顺序不可控
- 观察者过多时可能影响性能
- 可能导致循环依赖
- 观察者不知道彼此存在,可能导致更新冲突
实际应用案例
- 聊天系统:聊天室作为主题,用户作为观察者
- 温度监控系统:温度传感器作为主题,显示设备和报警系统作为观察者
- 彩票系统:彩票中心作为主题,购彩者作为观察者
- 企业监控系统:员工电脑作为主题,安全模块作为观察者