观察者模式

一、概述

观察者模式是一种行为设计模式,允许对象间存在一对多的依赖关系 ,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新 。在这种模式中,发生状态改变的对象被称为"主题"(Subject),依赖它的对象被称为"观察者"(Observer)。

观察者模式 (Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。

让我们通过一个简单的例子来实现观察者模式。假设我们有一个气象站(WeatherStation),需要向许多不同的显示设备(如手机App、网站、电子屏幕等)提供实时天气数据。

首先,我们需要创建一个Subject接口,表示主题

java 复制代码
/**
 * 被观察对象(主题)
 * @author: lemon
 * @date: 2024/4/26 13:08
 **/
public interface Subject {

    //1.添加观察者
    void registerObserver(Observer observer);

    //2.移除观察者
    void removeObserver(Observer observer);

    //3.通知观察者
    void notifyObserver();
}

接下来,我们创建一个Observer接口,表示观察者

java 复制代码
/**
 * 观察者
 * @author: lemon
 * @date: 2024/4/26 13:08
 **/
public interface Observer {
    void update(float temperature);
}

现在,我们创建一个具体的主题,如WeatherStation,实现Subject接口:

java 复制代码
/**
 * @Description: 气象站(被观察对象)---主题
 * @Author: lemon
 * @CreateTime: 2024-04-26  13:15
 * @Version: 1.0
 */
public class WeatherStation implements Subject{

    //温度
    private float temperature;

    //1.创建一个集合,用来保存观察者
    List<Observer> observerList;

    public WeatherStation() {
        observerList = new ArrayList<>();
    }


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

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

    //通知每一个客户端
    @Override
    public void notifyObserver() {
        for (Observer observer : observerList) {
            observer.update(temperature);
        }
    }

    //更新温度
    public void changeTemperature(float temperature){
        this.temperature = temperature;
        notifyObserver();
    }
}

最后,我们创建两个具体的观察者,实现Observer接口:

java 复制代码
public class AppClient implements Observer{
    @Override
    public void update(float temperature) {
        System.out.println("气象站更新温度,App温度为:" + temperature);
    }
}

public class WebClient implements Observer{
    @Override
    public void update(float temperature) {
        System.out.println("气象站更新温度,网站温度为:" + temperature);
    }
}

现在我们可以创建一个WeatherStation实例并向其注册观察者。当WeatherStation的数据发生变化时,两个观察者会收到通知并更新自己的显示。

java 复制代码
public class Test {
    public static void main(String[] args) {
        //1.创建气象站和观察者
        WeatherStation weatherStation = new WeatherStation();
        Observer appClient = new AppClient();
        Observer webClient = new WebClient();
        //2.添加观察者
        weatherStation.registerObserver(appClient);
        weatherStation.registerObserver(webClient);
        //3.气象站改变温度
        weatherStation.changeTemperature(25.4F);
    }
}

二、发布订阅

发布-订阅模式观察者模式 都是用于实现对象间的松耦合通信的设计模式。尽管它们具有相似之处,但它们在实现方式和使用场景上存在一些关键区别。他们在概念上有一定的相似性,都是用于实现对象间的松耦合通信 。可以将发布-订阅模式看作是观察者模式的一种变体或扩展。

两种模式的区别:

1、观察者模式:

观察者模式定义了一种一对多的依赖关系,当一个对象(被观察者)的状态发生变化时,所有依赖于它的对象(观察者)都会得到通知并自动更新。在这个模式中,被观察者和观察者之间存在直接的关联关系。观察者模式主要包括两类对象:被观察者(Subject)和观察者(Observer)。

2、发布订阅模式:

发布订阅模式引入了一个第三方组件(通常称为消息代理或事件总线) ,该组件负责维护发布者和订阅者之间的关系。这意味着发布者和订阅者彼此不直接通信 ,而是通过消息代理进行通信。这种间接通信允许发布者和订阅者在运行时动态地添加或删除,从而提高了系统的灵活性和可扩展性

还是使用上面的案例,用发布订阅的模式来实现:

首先,我们创建一个Subscriber接口,用于表示订阅者

java 复制代码
public interface Subscriber {
    //当发生某件事情时,执行对应行为
    void onEvent(Map<String, Object> event);
}

接下来,我们创建一个EventBus类,用于管理发布者和订阅者之间的通信:

java 复制代码
/**
 * @Description: 消息代理
 * @Author: lemon
 * @CreateTime: 2024-04-26  15:42
 * @Version: 1.0
 */
public class EventBus {

    //维护消息类型和订阅者的关系
    private final Map<String, List<Subscriber>> subscribers = new HashMap<>(2);

    //添加观察者(订阅关系)
    public void registerSubscriber(String eventType, Subscriber subscriber) {
        List<Subscriber> subscriberList = subscribers.computeIfAbsent(eventType, k -> new ArrayList<>());
        subscriberList.add(subscriber);
    }

    //移除观察者(解除订阅关系)
    public void removeSubscriber(String eventType, Subscriber subscriber) {
        List<Subscriber> subscriberList = subscribers.get(eventType);
        if (subscriberList != null) {
            subscriberList.remove(subscriber);
        }
    }


    //发布消息(状态改变)
    public void publishEvent(String eventType, Map<String, Object> event) {
        List<Subscriber> subscriberList = subscribers.get(eventType);
        if(subscriberList != null){
            for (Subscriber subscriber : subscriberList) {
                subscriber.onEvent(event);
            }
        }
    }
}

然后,我们创建两个具体的订阅者实现:

java 复制代码
public class AppSubscriber implements Subscriber{
    @Override
    public void onEvent(Map<String, Object> event) {
        System.out.println("app已更新最新温度:" + event.get("tmp"));
    }
}

public class WebSubscriber implements Subscriber{
    @Override
    public void onEvent(Map<String, Object> event) {
        System.out.println("web已更新最新温度:" + event.get("tmp"));
    }
}

最后,定义一个主题和客户端:

java 复制代码
/**
 * @Description: 气象站
 * @Author: lemon
 * @CreateTime: 2024-04-26  15:58
 * @Version: 1.0
 */
public class WeatherStation {

    private EventBus eventBus;

    public WeatherStation(EventBus eventBus) {
        this.eventBus = eventBus;
    }

    public void changeTemperature(float temperature){
        Map<String, Object> event = new HashMap<>();
        event.put("tmp", temperature);
        eventBus.publishEvent("temperature", event);
    }

    public static void main(String[] args) {
        //1.创建订阅者
        AppSubscriber appSubscriber = new AppSubscriber();
        WebSubscriber webSubscriber = new WebSubscriber();

        //2.构建消息代理
        EventBus bus = new EventBus();
        bus.registerSubscriber("temperature", appSubscriber);
        bus.registerSubscriber("temperature", webSubscriber);

        //3.发布消息
        WeatherStation weatherStation = new WeatherStation(bus);
        weatherStation.changeTemperature(25.6F);
    }
}

总结一下两者的区别:

  1. 通信方式:观察者模式中,观察者与被观察者之间存在直接的关联关系,而发布-订阅模式中,发布者和订阅者通过一个第三方组件(消息代理或事件总线)进行通信,彼此之间不存在直接关联关系。
  2. 系统复杂性:发布-订阅模式引入了一个额外的组件(消息代理或事件总线),增加了系统的复杂性,但同时也提高了系统的灵活性和可扩展性。
  3. 使用场景:观察者模式适用于需要将状态变化通知给其他对象的情况,而发布-订阅模式适用于事件驱动的系统,尤其是那些需要跨越多个模块或组件进行通信的场景。
相关推荐
蓝田~24 分钟前
观察者模式和订阅模式
windows·观察者模式
Mr. zhihao4 天前
从业务场景学习观察者模式
学习·观察者模式
Mr. zhihao4 天前
观察者模式 vs 不使用观察者模式:商品库存变化的通知
java·观察者模式
zgy11112229 天前
高阶函数全解析(定义、应用 -- 函数柯理化 反柯理化 发布订阅模式 观察者模式)
观察者模式
杨充9 天前
13.观察者模式设计思想
java·redis·观察者模式
G皮T10 天前
【设计模式】行为型模式(一):模板方法模式、观察者模式
java·观察者模式·设计模式·模板方法模式·template method·行为型模式·observer
小牛itbull11 天前
JavaScript 观察者设计模式
开发语言·javascript·观察者模式
孤邑12 天前
【设计模式】观察者模式
c++·笔记·学习·观察者模式·设计模式
霁月风15 天前
设计模式——观察者模式
c++·观察者模式·设计模式
金池尽干15 天前
设计模式之——观察者模式
观察者模式·设计模式