【设计模式】观察者模式

一、什么是观察者模式

概念:

  • 观察者模式(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来发布事件。

相关推荐
那你为何对我三笑留情28 分钟前
六、Spring Boot集成Spring Security之前后分离项目认证流程最佳方案
java·spring boot·分布式·后端·spring·spring security
土小帽软件测试30 分钟前
jmeter基础01-2_环境准备-Mac系统安装jdk
java·测试工具·jmeter·macos·软件测试学习
黎明晓月42 分钟前
Java之字符串分割转换List
java·windows·list
slp_1 小时前
java list使用基本操作
java·开发语言·list
王佑辉1 小时前
【java】ArrayList与LinkedList的区别
java
希忘auto1 小时前
详解Java之Spring MVC篇二
java·spring·mvc
乔冠宇1 小时前
环状 DNA 序列的最小表示法
java·数据结构·算法
星沁城2 小时前
73. 矩阵置零
java·算法·矩阵
Be_Somebody2 小时前
Maven的顶级功能——依赖管理
java·spring·spring入门