Java 观察者模式 3 种实现对比:原生接口 vs 自定义 vs 事件驱动
Java 观察者模式 3 种实现对比:原生接口 vs 自定义 vs 事件驱动
观察者模式是软件设计中最常用的行为型模式之一,它定义了对象间一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动收到通知。在Java生态中,实现观察者模式主要有三种典型方式:使用Java原生 Observable/Observer 接口、自定义观察者接口,以及基于Spring框架的事件驱动模型。本文将深入剖析这三种实现方式的优劣,并通过完整代码示例展示其应用场景。
1. 观察者模式核心概念
观察者模式(Observer Pattern)又称为发布-订阅模式(Publish-Subscribe),包含两个核心角色:
- Subject(主题) :维护观察者列表,提供注册/注销方法,状态变更时通知所有观察者
- Observer(观察者) :定义更新接口,用于接收主题通知
模式优势在于解耦主题与观察者,使得:
- 主题无需关心具体观察者类型
- 可以动态添加/移除观察者
- 符合开闭原则(对扩展开放,对修改关闭)
典型应用场景包括:
- GUI事件处理(如按钮点击事件)
- 分布式系统的消息通知
- 监控系统状态变化
- MVC模式中的模型-视图同步
2. Java原生实现:Observable/Observer
Java在 java.util 包中提供了内置的观察者模式实现,包含两个关键类:
// 被观察者继承java.util.Observable
public class WeatherData extends Observable {
private float temperature;
public void setMeasurements(float temp) {
this.temperature = temp;
setChanged(); // 标记状态已改变
notifyObservers(); // 无参通知
}
public float getTemperature() {
return temperature;
}
}
// 观察者实现java.util.Observer接口
public class CurrentConditionsDisplay implements Observer {
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData data = (WeatherData)o;
System.out.println("当前温度: " + data.getTemperature());
}
}
}
// 使用示例
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay display = new CurrentConditionsDisplay();
weatherData.addObserver(display);
weatherData.setMeasurements(25.5f);
优点 :
- 开箱即用,无需额外实现
- 线程安全的通知机制(
notifyObservers方法同步)
缺点 :
Observable是类而非接口,限制了复用- 无法实现更精细的通知控制
- JDK9后已被标记为
@Deprecated(since="9")
适用场景 :简单的单线程观察者需求,且不需要扩展 Observable 类功能的情况。
3. 自定义接口实现
更灵活的方式是自定义观察者接口,典型实现如下:
// 自定义主题接口
public interface Subject<T> {
void registerObserver(Observer<T> o);
void removeObserver(Observer<T> o);
void notifyObservers(T data);
}
// 自定义观察者接口
public interface Observer<T> {
void update(T data);
}
// 具体主题实现
public class ConcreteSubject implements Subject<String> {
private final Set<Observer<String>> observers = new CopyOnWriteArraySet<>();
@Override
public void registerObserver(Observer<String> o) {
observers.add(o);
}
@Override
public void notifyObservers(String data) {
observers.forEach(o -> o.update(data));
}
}
// 具体观察者实现
public class ConcreteObserver implements Observer<String> {
@Override
public void update(String data) {
System.out.println("收到数据: " + data);
}
}
关键优化点 :
- 使用泛型支持不同类型的数据通知
CopyOnWriteArraySet保证线程安全- 接口化设计符合依赖倒置原则
对比原生实现的优势 :
| 维度 | 原生实现 | 自定义实现 |
|---|---|---|
| 类型安全 | 使用Object传递数据 | 泛型支持 |
| 扩展性 | 受限于Observable类 | 完全自主控制 |
| 线程模型 | 同步通知 | 可灵活选择同步/异步 |
| 接口设计 | 类继承 | 接口实现 |
适用场景 :需要精细控制通知逻辑、支持多种数据类型或特殊线程模型的复杂场景。
4. Spring事件驱动模型
在Spring框架中,观察者模式通过事件机制实现,核心组件包括:
// 自定义事件(继承ApplicationEvent)
public class OrderCreatedEvent extends ApplicationEvent {
private String orderId;
public OrderCreatedEvent(Object source, String orderId) {
super(source);
this.orderId = orderId;
}
// getter...
}
// 发布者(注入ApplicationEventPublisher)
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
public void createOrder() {
// 业务逻辑...
publisher.publishEvent(new OrderCreatedEvent(this, "12345"));
}
}
// 监听器(实现ApplicationListener或使用@EventListener)
@Component
public class InventoryListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("处理订单创建: " + event.getOrderId());
}
}
Spring模型的独特优势 :
- 松耦合 :发布者与监听器通过事件对象交互,完全解耦
- 注解支持 :
@EventListener简化监听器定义 - 条件过滤 :支持
@EventListener(condition = "...") - 异步处理 :配合
@Async实现异步事件处理 - 事务绑定 :支持
@TransactionalEventListener绑定事务阶段
三种实现方式对比 :
| 特性 | Java原生 | 自定义接口 | Spring事件 |
|---|---|---|---|
| 实现复杂度 | 低 | 中 | 高 |
| 功能扩展性 | 差 | 优秀 | 优秀 |
| 线程控制 | 仅同步 | 可自定义 | 支持异步 |
| 框架依赖 | JDK内置 | 无 | 需Spring |
| 适用场景 | 简单同步通知 | 通用场景 | Spring应用 |
5. 高级应用与陷阱规避
5.1 内存泄漏防护
观察者模式常见的内存泄漏场景:
// 错误示例:观察者未及时注销
public class LeakDemo {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
while(true) {
Observer observer = new ConcreteObserver();
subject.registerObserver(observer);
// 忘记调用removeObserver
}
}
}
解决方案 :
- 使用弱引用(WeakReference)存储观察者
- 显式提供注销接口并在适当时机调用
- 对于集合类观察者,使用
WeakHashMap存储
5.2 性能优化策略
当观察者数量庞大时,可采用:
// 分级通知示例
public class HierarchicalNotifier {
private Map<EventType, Set<Observer>> observersByType = new EnumMap<>(EventType.class);
public void notifyObservers(EventType type, Object data) {
observersByType.getOrDefault(type, Collections.emptySet())
.forEach(o -> o.update(data));
}
}
其他优化技巧:
- 对高频事件采用批量通知
- 使用享元模式复用观察者实例
- 对IO密集型观察者采用异步处理
5.3 分布式观察者模式
在微服务架构中,可通过以下方式实现跨服务观察:
// 使用Spring Cloud Stream实现跨服务事件
@EnableBinding(Source.class)
public class DistributedEventPublisher {
@Autowired
private Source source;
public void publishEvent(String message) {
source.output().send(MessageBuilder.withPayload(message).build());
}
}
// 消费者端
@StreamListener(Sink.INPUT)
public void handleMessage(String message) {
System.out.println("Received: " + message);
}
6. 设计模式组合应用
观察者模式常与其他模式协同工作:
与中介者模式结合 :
// 使用中介者管理复杂观察关系
public class NotificationMediator {
private Map<String, List<Observer>> topicSubscribers = new HashMap<>();
public void subscribe(String topic, Observer observer) {
topicSubscribers.computeIfAbsent(topic, k -> new ArrayList<>()).add(observer);
}
public void publish(String topic, Object message) {
topicSubscribers.getOrDefault(topic, Collections.emptyList())
.forEach(o -> o.update(message));
}
}
与责任链模式结合 :
// 观察者形成处理链
public class ChainedObserver implements Observer {
private Observer next;
@Override
public void update(Object data) {
if(canHandle(data)) {
// 处理逻辑...
} else if(next != null) {
next.update(data);
}
}
}
在实际项目中,观察者模式的实现选择需综合考虑以下因素:
- 项目架构(是否使用Spring等框架)
- 性能要求(同步/异步,吞吐量需求)
- 扩展性需求(是否需要支持多种事件类型)
- 团队技术栈熟悉度
对于新启动的Spring项目,推荐优先使用Spring事件机制;而在基础组件开发或非Spring环境中,自定义接口实现提供了最大的灵活性。Java原生实现虽简单但已逐渐被更现代的方案取代。
更多推荐
所有评论(0)