文章目录
- 0.个人感悟
- [1. 概念](#1. 概念)
- [2. 适配场景](#2. 适配场景)
-
- [2.1 适合的场景](#2.1 适合的场景)
- [2.2 常见场景举例](#2.2 常见场景举例)
- [3. 实现方法](#3. 实现方法)
-
- [3.1 实现思路](#3.1 实现思路)
- [3.2 UML类图](#3.2 UML类图)
- [3.3 代码示例](#3.3 代码示例)
-
- [3.3.1 自己实现](#3.3.1 自己实现)
- [3.3.2 pro版:使用Java内置观察者模式java.util.Observer](#3.3.2 pro版:使用Java内置观察者模式java.util.Observer)
- [3.3.3 plus版:java.beans.PropertyChangeSupport](#3.3.3 plus版:java.beans.PropertyChangeSupport)
- [4. 优缺点](#4. 优缺点)
-
- [4.1 优点](#4.1 优点)
- [4.2 缺点](#4.2 缺点)
- [5. 源码分析](#5. 源码分析)
0.个人感悟
- 观察者模式,如名,希望建立对象之间的监听关系,使得被监听的信息能够通知到监听者
- 工作中我们可能习惯于使用框架的监听功能或者消息三方件。学习这个模式让我有点溯源的感觉。
- 提出模式,jdk 提供了java.util.Observable相关实现,可以满足基础需求
- jdk9开始Observable废弃,引入PropertyChangeSupport,跟踪源码,明显更加灵活
- 框架的诞生,出现了很多成熟的方案,比如spring的event
- 分布式,多节点,除了kafka等三方件
- 跟踪源码很有帮助,不仅可以帮助理解设计思路,同时有利于工作中快速使用api和定位bug(0.0)
- 这篇博客写的有些久,主要是实例代码写了好几版,虽然可能还是没讲明白,不过敲的代码都是自己理解到的,希望对大家有帮助
- 感谢优秀的博客,看到很多先驱者,感谢
1. 概念
英文定义 (《设计模式:可复用面向对象软件的基础》)
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
中文翻译
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
理解
- 核心思想:建立一种发布-订阅机制
- 解耦关键:被观察者(Subject)不知道观察者(Observer)的具体实现,只知道其接口
- 通信方式:通过接口回调实现通知
2. 适配场景
2.1 适合的场景
- 事件驱动系统:当一个对象状态变化需要通知其他多个对象时
- GUI事件处理:如按钮点击、鼠标移动等事件的监听
- 数据监控:监控数据变化并通知相关组件更新
- 消息通知系统:如邮件订阅、价格变动提醒
- MVC架构:Model数据变化时自动更新View
2.2 常见场景举例
- 电商系统:商品价格变化通知已收藏用户
- 气象系统:气象站数据变化更新多个显示设备
- 社交媒体:用户发布动态通知所有粉丝
- 股票交易:股价变动通知所有订阅者
- 物流系统:包裹状态变化通知相关方
3. 实现方法
3.1 实现思路
- 定义观察者接口:声明更新方法(update)
- 定义被观察者抽象类/接口:提供注册、移除和通知观察者的方法
- 实现具体被观察者:维护观察者列表,状态变化时通知所有观察者
- 实现具体观察者:实现更新方法,定义接收到通知后的行为
- 客户端使用:创建被观察者和观察者对象,建立订阅关系
3.2 UML类图

角色说明:
- Subject(被观察者):定义注册、移除和通知观察者的接口
- ConcreteSubject(具体被观察者):实现Subject接口,维护观察者列表,状态变化时通知
- Observer(观察者):定义更新接口
- ConcreteObserver(具体观察者):实现Observer接口,定义具体更新逻辑
3.3 代码示例
以关注商品降价通知实现为例
3.3.1 自己实现
思路 :根据模式思路自己来实现

观察者接口:
- 定义通知(回调的方法) ,这里的msg也可以是约定的一个参数对象,这里便于演示,直接string
java
public interface PriceObserver {
/**
* @param msg 消息
* @description 价格变化通知
* @author bigHao
* @date 2026/1/22
**/
void onPriceDrop(String msg);
}
被观察者: 定义增删观察者的接口和通知接口
java
public interface Subject {
/**
* @param priceObserver 观察者
* @description 添加观察者
* @author bigHao
* @date 2026/1/22
**/
void attach(PriceObserver priceObserver);
/**
* @param priceObserver 观察者
* @description 删除观察者
* @author bigHao
* @date 2026/1/22
**/
void detach(PriceObserver priceObserver);
/**
* @param msg 约定消息格式,比如json字符串
* @description 通知
* @author bigHao
* @date 2026/1/22
**/
void notifyObservers(String msg);
}
具体被观察者: 商品。
- 实现方法: 这里内置一个观察者列表
- 添加自己触发通知的方法: 降价
java
public class Product implements Subject {
private String name;
// 商品价格 被观察者state
private double price;
private List<PriceObserver> observers = new ArrayList<>();
public Product(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public void attach(PriceObserver priceObserver) {
observers.add(priceObserver);
System.out.println();
}
@Override
public void detach(PriceObserver priceObserver) {
observers.remove(priceObserver);
}
@Override
public void notifyObservers(String msg) {
observers.forEach(item -> {
item.onPriceDrop(msg);
});
}
/**
* @param newPrice 新的价格
* @description 价格变化
* @author bigHao
* @date 2026/1/22
**/
public void updatePrice(double newPrice) {
if (newPrice < price) {
String msg = STR."\{name} 原价 \{price} 降价到 \{newPrice}";
System.out.println(msg);
this.price = newPrice;
notifyObservers(msg);
} else {
this.price = newPrice;
}
}
}
具体被观察者:用户
java
public class User implements PriceObserver {
private String name;
public User(String name) {
this.name = name;
}
@Override
public void onPriceDrop(String msg) {
// 这里可以解析msg 比如字符串转对象
System.out.println(STR."收到通知: \{msg} 笑醒了!");
}
}
测试:
java
public class Client {
static void main() {
System.out.println("======自己实现====");
// 具体产品
Product rtx5090 = new Product("rtx5090",30000);
// 观察者
User observer1 = new User("Tom");
User observer2 = new User("Jack");
// 添加观察者
rtx5090.attach(observer1);
rtx5090.attach(observer2);
// 产品价格更新
System.out.println("=== 降价到23000 ===");
rtx5090.updatePrice(23000);
System.out.println("=== 降价到20000 ===");
rtx5090.updatePrice(20000);
}
}
输出:
======自己实现====
=== 降价到23000 ===
rtx5090 原价 30000.0 降价到 23000.0
收到通知: rtx5090 原价 30000.0 降价到 23000.0 笑醒了!
收到通知: rtx5090 原价 30000.0 降价到 23000.0 笑醒了!
=== 降价到20000 ===
rtx5090 原价 23000.0 降价到 20000.0
收到通知: rtx5090 原价 23000.0 降价到 20000.0 笑醒了!
收到通知: rtx5090 原价 23000.0 降价到 20000.0 笑醒了!
3.3.2 pro版:使用Java内置观察者模式java.util.Observer
思路 : java内置的观察者模式,其实思路和观察者模式一样,只是观察者和被观察者都集成到了sdk中。由于扩展性差,java9已过时,不过可以学习其思想

观察者:
- update方法会回传被观察对象和参数
java
package java.util;
@Deprecated(since="9")
public interface Observer {
void update(Observable o, Object arg);
}
被观察者:
- Vector持有观察者列表
- 注意这个changed,用于这个类状态是否变化,在notifyObservers会用到着开关
java
package java.util;
@Deprecated(since="9")
@SuppressWarnings("doclint:reference") // cross-module links
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
具体被观察者:
- 注意调用
setChanged()
java
public class Product extends Observable {
private String name;
private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public void updatePrice(double newPrice) {
if (newPrice < price) {
String msg = STR."\{name} 原价 \{price} 降价到 \{newPrice}";
System.out.println(msg);
this.price = newPrice;
// 注意这里要设置下状态,因为notifyObservers中有个开关 if (!changed)
setChanged();
notifyObservers(msg);
} else {
this.price = newPrice;
}
}
}
具体观察者:
java
public class User implements Observer {
private String name;
public User(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
// 这里需要类型判断
if (o instanceof Product) {
Product product = (Product) o;
// 通知参数是object 需要转换
String msg = (String) arg;
System.out.println(STR."收到通知: \{msg} 笑醒了!");
}
}
}
测试:
java
public class Client {
static void main() {
System.out.println("======jdk observer 实现====");
// 具体产品
Product rtx5090 = new Product("rtx5090",30000);
// 观察者
User observer1 = new User("Tom");
User observer2 = new User("Jack");
// 添加观察者
rtx5090.addObserver(observer1);
rtx5090.addObserver(observer2);
// 产品价格更新
System.out.println("=== 降价到23000 ===");
rtx5090.updatePrice(23000);
System.out.println("=== 降价到20000 ===");
rtx5090.updatePrice(20000);
}
}
结果:
======jdk observer 实现====
=== 降价到23000 ===
rtx5090 原价 30000.0 降价到 23000.0
收到通知: rtx5090 原价 30000.0 降价到 23000.0 笑醒了!
收到通知: rtx5090 原价 30000.0 降价到 23000.0 笑醒了!
=== 降价到20000 ===
rtx5090 原价 23000.0 降价到 20000.0
收到通知: rtx5090 原价 23000.0 降价到 20000.0 笑醒了!
收到通知: rtx5090 原价 23000.0 降价到 20000.0 笑醒了!
3.3.3 plus版:java.beans.PropertyChangeSupport
这是对观察者模式的扩展,更加灵活,扩展点在代码中会提到

整体设计思想:
- 事件封装成对象,包括足够信息,便于监听者处理数据
- 支持指定主题监听-推送,也就是说除了监听对象外,还扩展了一层
整体实现: - 引入PropertyChangeEvent封装事件参数,包括监听的对象、属性、新旧值等
- 引入PropertyChangeSupport来协助监听。也就是说不需要继承被监听者,而是通过依赖的方式进行监听
- 支持按propertyName监听,也就是说,可以只监听对象的个别属性,更加灵活。看后面的代码会更清晰,重点关注PropertyChangeSupport推送机制
事件: - 封装事件参数,回调时甚至可以把监听的对象source返回来
java
package java.beans;
public class PropertyChangeEvent extends EventObject {
public PropertyChangeEvent(Object source, String propertyName,
Object oldValue, Object newValue) {
super(source);
this.propertyName = propertyName;
this.newValue = newValue;
this.oldValue = oldValue;
}
}
观察者接口:
- 传入PropertyChangeEvent,可以理解为观察者、被观察者的参数bean
java
package java.beans;
public interface PropertyChangeListener extends java.util.EventListener {
void propertyChange(PropertyChangeEvent evt);
}
观察者support:
- 不是继承它来使用,而是依赖它,更加灵活,构造方法PropertyChangeSupport(Object sourceBean),sourceBean即被观察对象,也是PropertyChangeEvent中的source
- addPropertyChangeListener是重载方法,支持通用监听(监听所有事件)和按属性监听。具体实现是
PropertyChangeListenerMap 类似 propertyName-List<listener>的结构,通用监听的key是null(所以map会有一个null key ) - 构造事件,构建event对象,可以指定根据propertyName
- 事件推送时,根据event.propertyName 和 map.key匹配,找到listeners进行推送
java
public class PropertyChangeSupport implements Serializable {
private Object source;
private PropertyChangeListenerMap map = new PropertyChangeListenerMap();
// 构造函数
public PropertyChangeSupport(Object sourceBean) {
if (sourceBean == null) {
throw new NullPointerException();
}
source = sourceBean;
}
// 通用监听,监听所有属性变化
public void addPropertyChangeListener(PropertyChangeListener listener) {
if (listener == null) {
return;
}
if (listener instanceof PropertyChangeListenerProxy) {
PropertyChangeListenerProxy proxy =
(PropertyChangeListenerProxy)listener;
// Call two argument add method.
addPropertyChangeListener(proxy.getPropertyName(),
proxy.getListener());
} else {
this.map.add(null, listener);
}
}
// 按属性监听
public void addPropertyChangeListener(
String propertyName,
PropertyChangeListener listener) {
if (listener == null || propertyName == null) {
return;
}
listener = this.map.extract(listener);
if (listener != null) {
this.map.add(propertyName, listener);
}
}
// 发起事件
public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
}
}
public void firePropertyChange(PropertyChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
String name = event.getPropertyName();
PropertyChangeListener[] common = this.map.get(null);
PropertyChangeListener[] named = (name != null)
? this.map.get(name)
: null;
fire(common, event);
fire(named, event);
}
}
}
被监听者:
java
public class Product {
public static final String PRICE = "price";
public static final String SELT_MSG = "selfMsg";
private String name;
private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
private final PropertyChangeSupport support = new PropertyChangeSupport(this);
public void attach(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
public void attachPrice(PropertyChangeListener listener) {
support.addPropertyChangeListener(PRICE, listener);
}
public void attachSelfMsg(PropertyChangeListener listener) {
support.addPropertyChangeListener(SELT_MSG, listener);
}
public void detach(PropertyChangeListener listener) {
support.removePropertyChangeListener(listener);
}
public void updatePrice(double newPrice) {
if (newPrice < price) {
String msg = STR."\{name} 原价 \{price} 降价到 \{newPrice}";
System.out.println(msg);
// 这里会构建PropertyChangeEvent对象: new PropertyChangeEvent(this.source, propertyName, oldValue, newValue)
System.out.println("发送price事件");
support.firePropertyChange(PRICE, this.price, newPrice);
System.out.println("发送self事件");
support.firePropertyChange(SELT_MSG, null, msg);
this.price = newPrice;
} else {
this.price = newPrice;
}
}
@Override
public String toString() {
return STR."Product{name='\{name}', price=\{price}}";
}
}
具体监听者: 实现PropertyChangeListener接口
java
public class User implements PropertyChangeListener {
private String name;
public User(String name) {
this.name = name;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
Object source = evt.getSource();
Product product = (Product) source;
System.out.println(STR."\{name} 收到事件: ");
System.out.println("propertyName :" + propertyName);
System.out.println("oldValue :" + oldValue);
System.out.println("newValue :" + newValue);
System.out.println("product :" + product);
}
}
测试:
java
public class Client {
static void main() {
System.out.println("======jdk PropertyChangeSupport实现====");
// 具体产品
Product rtx5090 = new Product("rtx5090", 30000);
User tom = new User("tom");
User jack = new User("jack");
User mary = new User("mary");
// tom监听有类型事件
rtx5090.attach(tom);
// jack监听price事件
rtx5090.attachPrice(jack);
// mary监听self事件
rtx5090.attachSelfMsg(mary);
// 这里会发送price和self事件
rtx5090.updatePrice(25000);
}
}
结果:
java
public class Client {
static void main() {
System.out.println("======jdk PropertyChangeSupport实现====");
// 具体产品
Product rtx5090 = new Product("rtx5090", 30000);
User tom = new User("tom");
User jack = new User("jack");
User mary = new User("mary");
// tom监听有类型事件
rtx5090.attach(tom);
// jack监听price事件
rtx5090.attachPrice(jack);
// mary监听self事件
rtx5090.attachSelfMsg(mary);
// 这里会发送price和self事件
rtx5090.updatePrice(25000);
}
}
与传统方式对比:
- event参数化,更加灵活
- 继承被观察者的方式改为依赖,耦合轻
- 支持按propertyName监听
4. 优缺点
4.1 优点
-
高内聚低耦合
- 被观察者和观察者松耦合,可以独立变化
- 新增观察者无需修改被观察者代码
-
扩展性好
- 可以动态添加/删除观察者
- 支持广播通信,一对多通知
-
维护性高
- 观察者逻辑独立,便于维护和测试
- 支持运行时建立对象间关系
-
复用性强
- Observer接口可被多种具体观察者实现
- Subject可被多个不同场景复用
4.2 缺点
-
性能问题
- 观察者过多时,通知开销大
- 同步通知可能导致阻塞
-
稳定性风险 (循环依赖)
- 观察者间相互依赖可能导致循环调用
- 观察者更新失败可能影响其他观察者
5. 源码分析
有兴趣可以看看spring事件,这里也留个坑,会开spring专栏
参考: