观察者模式(Observer Pattern):事件通知与解耦的艺术
✨ 模式简介
观察者模式是一种行为型设计模式,定义了对象之间的一对多依赖关系,当一个对象(被观察者)状态改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。
就像微信公众号(被观察者)和订阅用户(观察者)的关系——公众号发布新文章时,所有订阅者都会自动收到推送。
📦 应用场景
GUI事件处理(按钮点击、键盘输入)
发布-订阅系统(如Kafka、Redis Pub/Sub)
状态监控(服务器健康检测)
数据变更通知(数据库->缓存同步)
Spring的事件驱动模型(
ApplicationEvent
)Vue/React的响应式系统
🧠 核心实现思路
Subject(主题):维护观察者列表,提供注册/注销方法
Observer(观察者):定义更新接口
ConcreteSubject(具体主题):状态变化时通知观察者
ConcreteObserver(具体观察者):实现更新逻辑
🧱 观察者模式的多种实现方式
1. 经典实现(手动管理)
// 观察者接口
interface Observer {
void update(String message);
}
// 主题接口
interface Subject {
void register(Observer o);
void remove(Observer o);
void notifyObservers();
}
// 具体主题
class NewsPublisher implements Subject {
private List<Observer> observers = new ArrayList<>();
private String latestNews;
public void setNews(String news) {
this.latestNews = news;
notifyObservers();
}
@Override
public void register(Observer o) {
observers.add(o);
}
@Override
public void notifyObservers() {
observers.forEach(o -> o.update(latestNews));
}
}
// 具体观察者
class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + "收到新闻:" + message);
}
}
2. Java内置支持(已过时但需了解)
import java.util.Observable;
import java.util.Observer;
// 继承Observable类
class WeatherStation extends Observable {
private float temperature;
public void setTemperature(float temp) {
this.temperature = temp;
setChanged(); // 标记状态变化
notifyObservers(temp); // 推模式通知
}
}
// 实现Observer接口
class Display implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("温度更新:" + arg + "°C");
}
}
3. 响应式流(Java9+ Flow API)
import java.util.concurrent.Flow.*;
import java.util.concurrent.SubmissionPublisher;
// 发布者
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
// 订阅者
class NewsSubscriber implements Subscriber<String> {
private Subscription subscription;
@Override
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
subscription.request(1); // 背压控制
}
@Override
public void onNext(String item) {
System.out.println("收到新闻:" + item);
subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
System.err.println("出错:" + throwable.getMessage());
}
@Override
public void onComplete() {
System.out.println("新闻推送结束");
}
}
// 使用
publisher.subscribe(new NewsSubscriber());
publisher.submit("Java 17发布啦!");
publisher.close();
4. Spring事件驱动(企业级推荐)
// 自定义事件
class OrderEvent extends ApplicationEvent {
private String orderId;
public OrderEvent(Object source, String orderId) {
super(source);
this.orderId = orderId;
}
// getter...
}
// 发布者
@Service
class OrderService {
@Autowired ApplicationEventPublisher publisher;
public void createOrder() {
// 业务逻辑...
publisher.publishEvent(new OrderEvent(this, "ORD-123"));
}
}
// 监听器(四种方式)
@Component
class NotificationListener {
// 方式1:注解监听
@EventListener
public void handleOrderEvent(OrderEvent event) {
System.out.println("处理订单事件:" + event.getOrderId());
}
// 方式2:实现接口
@Override // ApplicationListener<OrderEvent>
public void onApplicationEvent(OrderEvent event) {
// 处理逻辑
}
}
💎 最佳实践推荐
线程安全实现
// 使用CopyOnWriteArrayList避免并发修改异常
class SafeSubject implements Subject {
private List<Observer> observers = new CopyOnWriteArrayList<>();
@Override
public void register(Observer o) {
observers.add(o);
}
@Override
public void notifyObservers() {
observers.forEach(Observer::update);
}
}
异步事件处理
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.initialize();
return executor;
}
}
// 异步监听
@EventListener
@Async
public void handleAsyncEvent(OrderEvent event) {
// 耗时操作...
}
事件过滤与条件监听
// 条件化监听
@EventListener(condition = "#event.orderId.startsWith('VIP')")
public void handleVipOrder(OrderEvent event) {
System.out.println("处理VIP订单:" + event.getOrderId());
}
💣 常见问题与解决方案
问题1:观察者执行阻塞主线程?
✅ 解决方案:
使用异步观察者(线程池/消息队列)
Spring中配合
@Async
注解
问题2:观察者之间需要顺序执行?
✅ 解决方案:
使用
@Order
注解定义顺序手动维护观察者优先级列表
问题3:内存泄漏风险?
✅ 解决方案:
及时调用
removeObserver
使用弱引用(
WeakReference
)
📊 模式对比
📚 实际应用案例
Java Swing事件监听
button.addActionListener(e -> System.out.println("按钮被点击"));
ZooKeeper Watcher机制
zk.exists("/path", watchedEvent -> { System.out.println("节点变化:" + watchedEvent.getType()); });
Redis Pub/Sub
jedis.subscribe(new JedisPubSub() { @Override public void onMessage(String channel, String message) { System.out.println("收到消息:" + message); } }, "news-channel");
🎯 总结建议
优先选择:Spring事件驱动(企业应用)或响应式流(高并发)
性能优化:高频事件考虑批量通知
线程安全:使用
CopyOnWriteArrayList
或并发集合资源释放:及时注销观察者防止内存泄漏
设计原则:遵循松耦合原则,主题不应依赖具体观察者