观察者模式

发布于:2024-04-28 ⋅ 阅读:(31) ⋅ 点赞:(0)

一、概述

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

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

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

   

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

/**
 * 被观察对象(主题)
 * @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接口,表示观察者

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

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

/**
 * @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接口:

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的数据发生变化时,两个观察者会收到通知并更新自己的显示。

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接口,用于表示订阅者

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

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

/**
 * @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);
            }
        }
    }
}

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

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

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

/**
 * @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. 使用场景:观察者模式适用于需要将状态变化通知给其他对象的情况,而发布-订阅模式适用于事件驱动的系统,尤其是那些需要跨越多个模块或组件进行通信的场景。

网站公告

今日签到

点亮在社区的每一天
去签到