设计模式-观察者模式详解

观察者模式详解

目录

  1. 观察者模式简介
  2. 核心流程
  3. 重难点分析
  4. Spring中的源码分析
  5. 具体使用场景
  6. 面试高频点

观察者模式简介

定义

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。

核心思想

  • 解耦:观察者和被观察者之间松耦合
  • 通知机制:当状态改变时自动通知所有观察者
  • 动态关系:观察者可以动态地添加和删除

模式结构

  • Subject(主题/被观察者):定义添加、删除、通知观察者的接口
  • ConcreteSubject(具体主题):实现主题接口,维护观察者列表
  • Observer(观察者):定义更新接口
  • ConcreteObserver(具体观察者):实现观察者接口,定义具体的更新逻辑

核心流程

观察者模式流程图

观察者对象
主题对象
更新方法
业务逻辑
维护观察者列表
状态数据
通知方法
主题状态改变
调用notifyObservers
遍历观察者列表
调用每个观察者的update方法
观察者执行更新逻辑
观察者注册
调用addObserver
添加到观察者列表
观察者注销
调用removeObserver
从观察者列表移除

基本实现流程

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());
    }
}

面试高频点

面试知识点思维导图

观察者模式面试点
基本概念
实现方式
重难点
Spring应用
设计原则
实际应用
一对多依赖
解耦设计
通知机制
Subject接口
Observer接口
具体实现
客户端调用
内存泄漏
线程安全
执行顺序
异常处理
ApplicationEventPublisher
ApplicationListener
@EventListener注解
事件传播机制
开闭原则
依赖倒置
单一职责
用户注册
订单状态
缓存更新
系统监控

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框架中,观察者模式被广泛应用于事件驱动编程,提供了强大的解耦和扩展能力。

核心优势

  1. 松耦合:观察者和主题之间松耦合
  2. 动态关系:可以动态添加和删除观察者
  3. 开闭原则:易于扩展新的观察者
  4. 通知机制:自动通知所有观察者

注意事项

  1. 内存管理:注意观察者的生命周期管理
  2. 线程安全:多线程环境下的并发控制
  3. 异常处理:避免单个观察者异常影响其他观察者
  4. 性能考虑:大量观察者时的性能优化

在实际开发中,观察者模式特别适用于需要解耦的业务场景,如用户注册、订单状态变更、缓存更新等。通过合理使用观察者模式,可以大大提高代码的可维护性和扩展性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值