【设计模式】观察者模式

一、什么是观察者模式

概念:

  • 观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系, 一是指主题对象,多是指观察者对象,观察者对象监听主题对象的状态变化。当主题对象改变时,对应的观察者对象就会收到通知并更新自身。

角色组成:

  1. Subject(主题):即被观察者,它是一个抽象类或接口,定义了注册和撤销观察者对象的方法,以及通知观察者的方法。

  2. ConcreteSubject(具体主题):实现了主题接口,它具有添加、删除和通知观察者的功能,当其内部状态发生改变时,会通知所有注册的观察者。

  3. Observer(观察者):也称为订阅者或监听者,它是一个抽象类或接口,定义了观察者接收通知并更新自身的方法。

  4. ConcreteObserver(具体观察者):实现了观察者接口,收到主题的通知即会执行相应操作,以便与主题保持一致。

二、观察者模式的优点

  1. 解耦:主题和观察者独立封装,主题对象不需要知道观察者的具体实现,只需要通过观察者接口进行通信。

  2. 可扩展性:一个观察者对象的增删改不会影响其他对象通信,主题对象也不用修改代码,符合开闭原则。

  3. 通知机制:主题对象的状态发生改变时,会自动通知所有注册的观察者对象,即实现了对象间的动态通信。

  4. 易于维护:观察者模式的结构清晰,代码可读性好,每个角色的功能单一,易于理解和维护。

  5. 代码复用:由于观察者模式解耦了主题和观察者对象,使得它们可以被独立地复用,不需要修改原有的代码。

总之,观察者模式是一种灵活、可扩展且可维护的设计模式,适用于一对多的通信场景,常见于事件驱动的系统设计、图形界面框架、消息队列等场景中。

三、观察者模式的应用场景

  1. 需要通知时:当一个对象的状态改变需要通知其他对象,并且不知道通知的对象是谁时,可以使用观察者模式。例如,一个主题对象(被观察者)的状态变化需要通知多个观察者对象,比如电商平台上商品价格变化通知用户

  2. 需要解耦时:一个对象需要将自己的状态变化通知给其他对象,并且不关心其他对象的具体实现时,可以使用观察者模式。例如,一个发布者将消息发布给多个订阅者,而发布者不需要关心每个订阅者的处理方式

  3. 一对多依赖时:一个对象的改变会影响其他多个对象时,可以使用观察者模式。例如,一支股票的价格变化会影响到所有交易者的决策

示例:新闻订阅系统

假设有一个新闻发布者(被观察者)和多个新闻订阅者(观察者)。当新闻发布者发布一条新闻时,所有订阅者都会收到通知并更新自己的新闻列表。这个问题可以使用观察者模式来解决。

在该示例中,新闻发布者是主题对象,新闻订阅者是观察者对象。新闻发布者可以注册和删除订阅者,并且在发布新闻时会通知所有订阅者。订阅者可以更新自己的新闻列表。

通过使用观察者模式,新闻发布者和订阅者对象之间解耦,实现了一对多的通信机制,同时也方便了新闻发布者的扩展和维护。

四、观察者模式的Java实现

在Java中,可以通过以下步骤来实现观察者模式:

  1. 定义观察者接口(Observer):观察者接口中声明了更新方法,用于在被观察者状态变化时进行通知。
java 复制代码
public interface Observer {
    void update();
}
  1. 定义被观察者接口(Subject):被观察者接口中声明了添加、删除和通知观察者的方法。
java 复制代码
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
  1. 实现观察者类(具体观察者):具体观察者类实现了观察者接口,并实现了更新方法。
java 复制代码
public class ConcreteObserver implements Observer {
    @Override
    public void update() {
        // 执行更新操作
    }
}
  1. 实现被观察者类(具体被观察者):具体被观察者类实现了被观察者接口,并维护了观察者列表,实现了添加、删除和通知观察者的方法。
java 复制代码
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}
  1. 使用观察者模式:在实际应用中,可以创建具体观察者和具体被观察者对象,然后将观察者注册到被观察者中,并在需要的时候调用被观察者的通知方法。
java 复制代码
public class Main {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        ConcreteObserver observer1 = new ConcreteObserver();
        ConcreteObserver observer2 = new ConcreteObserver();
        
        subject.registerObserver(observer1);
        subject.registerObserver(observer2);
        
        // 状态变化后通知观察者
        subject.notifyObservers();
    }
}

以上,我们就完成了观察者模式的Java示例。在具体的应用场景中,可以根据需要扩展、修改和定制观察者模式的实现。

五、SpringBoot中观察者模式的实现

在Spring Boot中,可以使用Spring框架中的事件机制来实现观察者模式。Spring的事件机制基于观察者模式,通过发布-订阅模型实现。

实现Spring Boot中观察者模式的步骤如下:

  1. 定义事件类:创建一个继承自ApplicationEvent的自定义事件类。
java 复制代码
public class CustomEvent extends ApplicationEvent {
    public CustomEvent(Object source) {
        super(source);
    }
    
    // 可以定义一些自定义的属性和方法
}
  1. 定义观察者类:创建一个实现ApplicationListener接口的观察者类。
java 复制代码
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        // 在事件发生时,执行相应的逻辑
    }
}
  1. 发布事件:在需要的地方通过ApplicationContext来发布自定义事件。
java 复制代码
@Autowired
private ApplicationContext applicationContext;

public void publishEvent() {
    CustomEvent event = new CustomEvent(this);
    applicationContext.publishEvent(event);
}

通过上述步骤,我们就可以在Spring Boot中实现观察者模式。当发布自定义事件时,所有订阅该事件的观察者都会收到通知并执行相应的逻辑。可以根据需要在观察者类中进行逻辑处理,例如发送通知、更新数据等操作。

需要注意的是,在使用Spring的事件机制时,观察者类需要被Spring容器管理,可以通过@Component注解或者其他方式将观察者类注入到容器中。另外,发布事件的类需要通过@Autowired或者其他方式获取ApplicationContext来发布事件。

相关推荐
带刺的坐椅11 分钟前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看2 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程2 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t2 小时前
ZIP工具类
java·zip
lang201509282 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
pengzhuofan3 小时前
第10章 Maven
java·maven
百锦再4 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说4 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多4 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
百锦再4 小时前
对前后端分离与前后端不分离(通常指服务端渲染)的架构进行全方位的对比分析
java·开发语言·python·架构·eclipse·php·maven