观察者模式:一个被观察者(主题)状态变化,自动通知所有注册的观察者,触发更新,属于行为型设计模式。
JDK 原生也提供
java.util.Observer/Observable,不过已经标记废弃,下面手写一套标准实现,便于理解原理。
UML 角色
Subject(抽象主题 / 被观察者):注册、移除、通知观察者
ConcreteSubject(具体被观察者):维护状态,状态改变时发起通知
Observer(抽象观察者):接收更新回调接口
ConcreteObserver(具体观察者):实现更新逻辑
import java.util.ArrayList;
import java.util.List;
/**
* 抽象观察者接口
*/
interface Observer {
/**
* 被观察者通知时调用
* @param message 通知消息
*/
void update(String message);
}
/**
* 抽象被观察者(主题)
*/
abstract class Subject {
// 保存已注册观察者
protected final List<Observer> observerList = new ArrayList<>();
// 注册观察者
public void attach(Observer observer) {
observerList.add(observer);
}
// 移除观察者
public void detach(Observer observer) {
observerList.remove(observer);
}
// 通知所有观察者
public abstract void notifyObservers();
}
/**
* 具体被观察者:消息发布者
*/
class MessageSubject extends Subject {
private String message;
public void setMessage(String message) {
this.message = message;
// 状态变更,推送通知
notifyObservers();
}
@Override
public void notifyObservers() {
for (Observer observer : observerList) {
observer.update(message);
}
}
}
/**
* 具体观察者A:用户A
*/
class UserObserverA implements Observer {
private final String name;
public UserObserverA(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.printf("[%s] 收到消息通知:%s%n", name, message);
}
}
/**
* 具体观察者B:用户B
*/
class UserObserverB implements Observer {
private final String name;
public UserObserverB(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.printf("[%s] 收到消息通知:%s%n", name, message);
}
}
// 测试主类
public class ObserverDemo {
public static void main(String[] args) {
// 创建被观察者
MessageSubject subject = new MessageSubject();
// 创建观察者
Observer userA = new UserObserverA("张三");
Observer userB = new UserObserverB("李四");
// 订阅(注册)
subject.attach(userA);
subject.attach(userB);
System.out.println("===== 第一次消息推送 =====");
subject.setMessage("系统发布新版本V2.0");
// 取消订阅张三
subject.detach(userA);
System.out.println("\n===== 第二次消息推送(张三已取消订阅) =====");
subject.setMessage("服务器即将维护升级");
}
}
输出结果
===== 第一次消息推送 =====
[张三] 收到消息通知:系统发布新版本V2.0
[李四] 收到消息通知:系统发布新版本V2.0
===== 第二次消息推送(张三已取消订阅) =====
[李四] 收到消息通知:服务器即将维护升级
JDK 废弃 API 版本(了解即可,不推荐新项目使用)
java.util.Observable、java.util.Observer Java9+ @Deprecated
import java.util.Observable;
import java.util.Observer;
// 被观察者
class JdkSubject extends Observable {
public void publish(String msg) {
setChanged(); // 标记状态发生改变,必须调用
notifyObservers(msg);
}
}
public class JdkObserverDemo {
public static void main(String[] args) {
JdkSubject subject = new JdkSubject();
Observer obs = (o, arg) -> System.out.println("收到:" + arg);
subject.addObserver(obs);
subject.publish("jdk观察者消息");
}
}
缺点:Observable 是类不是接口,Java 单继承限制,灵活性差,所以废弃。生产项目建议手写自定义接口方式。
观察者模式优缺点
✅ 优点
观察者与被观察者松耦合,互不依赖具体实现
支持一对多广播通知,新增观察者不用修改主题代码,符合开闭原则
❌ 缺点
观察者过多,通知广播耗时;同步阻塞模式下某个观察者卡顿会影响全部通知
没有顺序保障,观察者执行顺序不可控;容易出现循环调用问题
常见业务场景
事件订阅:消息推送、事件总线
GUI 事件监听
MQ 消息消费、配置变更推送
Spring 的 ApplicationListener 事件机制底层就是观察者模式
本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问