观察者模式详解
目录
观察者模式简介
定义
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。
核心思想
- 解耦:观察者和被观察者之间松耦合
- 通知机制:当状态改变时自动通知所有观察者
- 动态关系:观察者可以动态地添加和删除
模式结构
- Subject(主题/被观察者):定义添加、删除、通知观察者的接口
- ConcreteSubject(具体主题):实现主题接口,维护观察者列表
- Observer(观察者):定义更新接口
- ConcreteObserver(具体观察者):实现观察者接口,定义具体的更新逻辑
核心流程
观察者模式流程图
基本实现流程
1. 定义观察者接口
public interface Observer {
void update(String message);
}
2. 定义主题接口
public interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
3. 实现具体主题
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String state;
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(state);
}
}
public void setState(String state) {
this.state = state;
notifyObservers(); // 状态改变时通知观察者
}
}
4. 实现具体观察者
public class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " 收到消息: " + message);
}
}
5. 客户端使用
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("观察者1");
Observer observer2 = new ConcreteObserver("观察者2");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.setState("状态已改变");
}
}
重难点分析
重难点1:内存泄漏问题
问题描述
观察者模式容易导致内存泄漏,特别是当观察者没有正确注销时。
解决方案
public class SubjectManager {
private static final Map<String, Subject> subjects = new ConcurrentHashMap<>();
public static void registerObserver(String subjectId, Observer observer) {
subjects.computeIfAbsent(subjectId, k -> new ConcreteSubject())
.addObserver(observer);
}
public static void unregisterObserver(String subjectId, Observer observer) {
Subject subject = subjects.get(subjectId);
if (subject != null) {
subject.removeObserver(observer);
// 如果没有观察者了,可以考虑清理subject
if (subject.getObserverCount() == 0) {
subjects.remove(subjectId);
}
}
}
}
重难点2:线程安全问题
问题描述
在多线程环境下,观察者列表的修改和遍历可能产生并发问题。
解决方案
public class ThreadSafeSubject implements Subject {
private final List<Observer> observers = Collections.synchronizedList(new ArrayList<>());
private final Object lock = new Object();
@Override
public void addObserver(Observer observer) {
synchronized (lock) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
}
@Override
public void removeObserver(Observer observer) {
synchronized (lock) {
observers.remove(observer);
}
}
@Override
public void notifyObservers() {
List<Observer> observersCopy;
synchronized (lock) {
observersCopy = new ArrayList<>(observers);
}
for (Observer observer : observersCopy) {
try {
observer.update(getState());
} catch (Exception e) {
// 处理观察者异常,避免影响其他观察者
System.err.println("观察者更新失败: " + e.getMessage());
}
}
}
}
重难点3:观察者执行顺序
问题描述
多个观察者的执行顺序可能影响业务逻辑。
解决方案
public class PriorityObserver implements Observer, Comparable<PriorityObserver> {
private final Observer observer;
private final int priority;
public PriorityObserver(Observer observer, int priority) {
this.observer = observer;
this.priority = priority;
}
@Override
public void update(String message) {
observer.update(message);
}
@Override
public int compareTo(PriorityObserver other) {
return Integer.compare(this.priority, other.priority);
}
}
public class OrderedSubject implements Subject {
private final List<PriorityObserver> observers = new ArrayList<>();
@Override
public void notifyObservers() {
// 按优先级排序后通知
observers.stream()
.sorted()
.forEach(observer -> observer.update(getState()));
}
}
重难点4:观察者异常处理
问题描述
某个观察者抛出异常可能影响其他观察者的执行。
解决方案
public class SafeObserverWrapper implements Observer {
private final Observer delegate;
private final String observerName;
public SafeObserverWrapper(Observer delegate, String observerName) {
this.delegate = delegate;
this.observerName = observerName;
}
@Override
public void update(String message) {
try {
delegate.update(message);
} catch (Exception e) {
// 记录异常但不影响其他观察者
System.err.println("观察者 " + observerName + " 执行失败: " + e.getMessage());
// 可以选择移除异常的观察者
// removeObserver(this);
}
}
}
Spring中的源码分析
ApplicationEventPublisher接口
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
AbstractApplicationContext中的实现
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
private ApplicationEventMulticaster applicationEventMulticaster;
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
@Override
public void publishEvent(Object event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// 包装事件
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
} else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
}
// 发布事件
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// 发布到父上下文
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
}
ApplicationEventMulticaster接口
public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener<?> listener);
void addApplicationListenerBean(String listenerBeanName);
void removeApplicationListener(ApplicationListener<?> listener);
void removeApplicationListenerBean(String listenerBeanName);
void removeAllListeners();
void multicastEvent(ApplicationEvent event);
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
SimpleApplicationEventMulticaster实现
public class SimpleApplicationEventMulticaster implements ApplicationEventMulticaster {
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
invokeListener(listener, event);
}
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void invokeListener(ApplicationListener listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
listener.onApplicationEvent(event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
listener.onApplicationEvent(event);
}
}
}
自定义事件示例
// 自定义事件
public class UserRegisteredEvent extends ApplicationEvent {
private final String username;
private final String email;
public UserRegisteredEvent(Object source, String username, String email) {
super(source);
this.username = username;
this.email = email;
}
public String getUsername() { return username; }
public String getEmail() { return email; }
}
// 事件监听器
@Component
public class UserEventListener {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
System.out.println("用户注册事件: " + event.getUsername());
// 发送欢迎邮件
sendWelcomeEmail(event.getEmail());
}
@EventListener
@Async
public void handleUserRegisteredAsync(UserRegisteredEvent event) {
// 异步处理
System.out.println("异步处理用户注册: " + event.getUsername());
}
private void sendWelcomeEmail(String email) {
// 发送邮件逻辑
}
}
// 事件发布者
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(String username, String email) {
// 注册用户逻辑
System.out.println("用户注册成功: " + username);
// 发布事件
eventPublisher.publishEvent(new UserRegisteredEvent(this, username, email));
}
}
具体使用场景
1. 用户注册系统
// 用户注册后需要执行多个操作
@Component
public class UserRegistrationService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(User user) {
// 保存用户
saveUser(user);
// 发布注册事件
eventPublisher.publishEvent(new UserRegisteredEvent(user));
}
}
// 发送欢迎邮件
@Component
public class WelcomeEmailListener {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
sendWelcomeEmail(event.getUser().getEmail());
}
}
// 初始化用户权限
@Component
public class UserPermissionListener {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
initializeUserPermissions(event.getUser());
}
}
2. 订单状态变更
// 订单状态变更事件
public class OrderStatusChangedEvent extends ApplicationEvent {
private final Order order;
private final OrderStatus oldStatus;
private final OrderStatus newStatus;
// 构造函数和getter方法
}
// 订单服务
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void updateOrderStatus(Long orderId, OrderStatus newStatus) {
Order order = getOrderById(orderId);
OrderStatus oldStatus = order.getStatus();
order.setStatus(newStatus);
saveOrder(order);
// 发布状态变更事件
eventPublisher.publishEvent(new OrderStatusChangedEvent(order, oldStatus, newStatus));
}
}
// 库存更新监听器
@Component
public class InventoryUpdateListener {
@EventListener
public void handleOrderStatusChanged(OrderStatusChangedEvent event) {
if (event.getNewStatus() == OrderStatus.CANCELLED) {
// 释放库存
releaseInventory(event.getOrder());
}
}
}
// 物流通知监听器
@Component
public class LogisticsNotificationListener {
@EventListener
public void handleOrderStatusChanged(OrderStatusChangedEvent event) {
if (event.getNewStatus() == OrderStatus.SHIPPED) {
// 通知物流
notifyLogistics(event.getOrder());
}
}
}
3. 缓存更新通知
// 缓存更新事件
public class CacheUpdateEvent extends ApplicationEvent {
private final String cacheKey;
private final Object oldValue;
private final Object newValue;
// 构造函数和getter方法
}
// 缓存服务
@Service
public class CacheService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void updateCache(String key, Object value) {
Object oldValue = getFromCache(key);
putToCache(key, value);
// 发布缓存更新事件
eventPublisher.publishEvent(new CacheUpdateEvent(key, oldValue, value));
}
}
// 分布式缓存同步监听器
@Component
public class DistributedCacheSyncListener {
@EventListener
public void handleCacheUpdate(CacheUpdateEvent event) {
// 同步到其他节点
syncToOtherNodes(event.getCacheKey(), event.getNewValue());
}
}
4. 系统监控和日志
// 系统事件
public class SystemEvent extends ApplicationEvent {
private final String eventType;
private final String message;
private final Map<String, Object> metadata;
// 构造函数和getter方法
}
// 系统监控服务
@Service
public class SystemMonitorService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void recordSystemEvent(String eventType, String message, Map<String, Object> metadata) {
eventPublisher.publishEvent(new SystemEvent(eventType, message, metadata));
}
}
// 日志记录监听器
@Component
public class LoggingListener {
@EventListener
public void handleSystemEvent(SystemEvent event) {
// 记录到日志文件
logger.info("系统事件: {} - {}", event.getEventType(), event.getMessage());
}
}
// 监控指标收集监听器
@Component
public class MetricsCollectorListener {
@EventListener
public void handleSystemEvent(SystemEvent event) {
// 收集监控指标
collectMetrics(event.getEventType(), event.getMetadata());
}
}
面试高频点
面试知识点思维导图
1. 观察者模式的基本概念
问题:什么是观察者模式?
答案要点:
- 定义一对多的依赖关系
- 当主题状态改变时,自动通知所有观察者
- 实现松耦合的设计
- 属于行为型设计模式
问题:观察者模式有哪些角色?
答案要点:
- Subject(主题):被观察的对象,维护观察者列表
- Observer(观察者):观察主题的对象,定义更新接口
- ConcreteSubject(具体主题):实现主题接口
- ConcreteObserver(具体观察者):实现观察者接口
2. 实现方式相关
问题:如何实现观察者模式?
答案要点:
// 1. 定义观察者接口
public interface Observer {
void update(String message);
}
// 2. 定义主题接口
public interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 3. 实现具体主题
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String state;
public void setState(String state) {
this.state = state;
notifyObservers();
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(state);
}
}
}
3. 重难点问题
问题:观察者模式有什么缺点?
答案要点:
- 内存泄漏:观察者没有正确注销
- 循环依赖:观察者和主题相互引用
- 性能问题:大量观察者时通知效率低
- 线程安全:多线程环境下的并发问题
- 执行顺序:观察者执行顺序不确定
问题:如何解决观察者模式的内存泄漏问题?
答案要点:
// 1. 使用WeakReference
public class WeakObserver implements Observer {
private WeakReference<Observer> delegate;
public WeakObserver(Observer delegate) {
this.delegate = new WeakReference<>(delegate);
}
@Override
public void update(String message) {
Observer observer = delegate.get();
if (observer != null) {
observer.update(message);
}
}
}
// 2. 及时注销观察者
public void cleanup() {
subject.removeObserver(this);
}
4. Spring中的应用
问题:Spring中如何使用观察者模式?
答案要点:
// 1. 定义事件
public class UserRegisteredEvent extends ApplicationEvent {
private final String username;
public UserRegisteredEvent(Object source, String username) {
super(source);
this.username = username;
}
}
// 2. 发布事件
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(String username) {
// 注册逻辑
eventPublisher.publishEvent(new UserRegisteredEvent(this, username));
}
}
// 3. 监听事件
@Component
public class UserEventListener {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
System.out.println("用户注册: " + event.getUsername());
}
}
问题:Spring事件机制的特点?
答案要点:
- 同步发布:默认同步执行
- 异步支持:使用@Async注解
- 事件传播:支持父子容器事件传播
- 类型安全:基于泛型的事件类型
- 异常处理:支持异常处理器
5. 设计原则相关
问题:观察者模式体现了哪些设计原则?
答案要点:
- 开闭原则:可以添加新的观察者而不修改主题
- 依赖倒置:依赖抽象而不是具体实现
- 单一职责:主题和观察者职责分离
- 里氏替换:观察者可以替换
6. 实际应用场景
问题:观察者模式适用于哪些场景?
答案要点:
- 用户注册:注册后发送邮件、初始化权限等
- 订单状态:状态变更后更新库存、通知物流等
- 缓存更新:数据变更后同步缓存
- 系统监控:记录日志、收集指标等
- UI更新:模型变更后更新视图
7. 与其他模式的对比
问题:观察者模式与发布-订阅模式的区别?
答案要点:
- 耦合度:观察者模式耦合度更高
- 通信方式:观察者模式直接调用,发布-订阅通过消息队列
- 扩展性:发布-订阅模式扩展性更好
- 性能:发布-订阅模式性能更好
问题:观察者模式与中介者模式的区别?
答案要点:
- 关系:观察者是一对多,中介者是多对多
- 职责:观察者负责通知,中介者负责协调
- 复杂度:中介者模式更复杂
- 使用场景:观察者用于状态通知,中介者用于对象协调
总结
观察者模式是一种重要的行为型设计模式,它通过定义一对多的依赖关系,实现了对象间的松耦合通信。在Spring框架中,观察者模式被广泛应用于事件驱动编程,提供了强大的解耦和扩展能力。
核心优势
- 松耦合:观察者和主题之间松耦合
- 动态关系:可以动态添加和删除观察者
- 开闭原则:易于扩展新的观察者
- 通知机制:自动通知所有观察者
注意事项
- 内存管理:注意观察者的生命周期管理
- 线程安全:多线程环境下的并发控制
- 异常处理:避免单个观察者异常影响其他观察者
- 性能考虑:大量观察者时的性能优化
在实际开发中,观察者模式特别适用于需要解耦的业务场景,如用户注册、订单状态变更、缓存更新等。通过合理使用观察者模式,可以大大提高代码的可维护性和扩展性。
341

被折叠的 条评论
为什么被折叠?



