《Head First 设计模式》学习笔记 -- 观察者模式

观察者模式:定义对象之间一对多的依赖,当一个对象状态改变会通知它所有依赖者自动更新。

我的理解: 这种模式类似于订阅通知功能,你是一个博主,你的关注者订阅了你,当你发布新的博客时,会发布通知告诉所有订阅者,你发新博客了。

在这里插入图片描述
观察者模式类图:

在这里插入图片描述
HeadFirst 案例分析:
气象站希望公布一组API,其他的开发者可以根据API开发出不同的气象布告板,气象数据会随时变更,要保证数据更新了同时通知所有布告板更新数据。
在这里插入图片描述
根据上图发现,不管多少个布告板,WeatherData这个对象都不会变,所以它在观察者模式一对多中的Subject,而布告板可以有多个,显而易见它就是Observer
在这里插入图片描述

自定义实现Subject/Observer

Subject 接口定义注册、删除以及通知观察者的接口方法

/**
 * @author zhaotianxin
 * @date 2021-07-20 20:25
 * 定义Subject接口,支持注册、删除、通知观察者
 */
public interface Subject {
    // 注册观察者
    void registerObserver(Observer observer);
    // 删除观察者
    void removeObserver(Observer observer);
    // 通知观察者
    void notifyObservers();
}

Observer 接口 提供更新接口

/**
 * @author zhaotianxin
 * @date 2021-07-20 20:27
 */
public interface Observer {
    void update(float temp, float humidity, float pressure);
}

WeatherData 类实现Subject接口, 并实现存储、注册、删除、通知观察者的逻辑

/**
 * @author zhaotianxin
 * @date 2021-07-20 20:30
 * 天气数据类,实现Subject接口
 */
public class WeatherData implements Subject{

    // 用于存储所有订阅此消息的观察者
    private List<Observer> observers;

    private float temp;

    private float humidity;

    private float pressure;

    public WeatherData() {
        observers = new ArrayList<>();
    }

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

    @Override
    public void removeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        if(index > 0 ){
            observers.remove(observer);
        }
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temp, humidity, pressure);
        }
    }

    /**
     * 数据发生变化调用此方法,通知观察者
     */
    public void dataChange(float temp, float humidity, float pressure){
        this.temp =temp;
        this.humidity =humidity;
        this.pressure =pressure;
        notifyObservers();
    }

WeatherApp : 根据WeatherData 的数据实现的一个 应用或者显示板,当前模式中的观察者。通过实例化时传入Subject 去实现注册。这种可以有多个

/**
 * @author zhaotianxin
 * @date 2021-07-20 20:37
 * 观察者1
 */
public class WeatherApp implements Observer {

    private float temp;

    private float humidity;

    private float pressure;

    private Subject weatherData;

    /***
     * 初始化实例时,传入Subject,将当前设置成观察者
     * @param subject
     */
    public  WeatherApp(Subject subject){
        this.weatherData = subject;
        subject.registerObserver(this);
    }
    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temp = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        display();
    }

    public void display(){
        System.out.println("观察者1数据更新:" +temp + "-" + humidity + "--"+ pressure);
    }
}
/**
 * @author zhaotianxin
 * @date 2021-07-20 20:37
 * 观察者2
 */
public class SmallWeatherApp implements Observer {

    private float temp;

    private float humidity;

    private float pressure;

    private Subject weatherData;

    /***
     * 初始化实例时,传入Subject,将当前设置成观察者
     * @param subject
     */
    public SmallWeatherApp(Subject subject){
        this.weatherData = subject;
        subject.registerObserver(this);
    }
    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temp = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        display();
    }

    public void display(){
        System.out.println("观察者2数据更新:" + temp + "-" + humidity + "--"+ pressure);
    }
}

调用实现:

public class ObserverMain {
    public static void main(String[] args) {
        // 初始化Subject
        WeatherData subject = new WeatherData();
        // 注册第一个观察者
        WeatherApp weatherApp = new WeatherApp(subject);
        // 注册第二个观察者
        SmallWeatherApp smallWeatherApp = new SmallWeatherApp(subject);

        // 发送第一波数据
        System.out.println("---------------第一次数据更新--------------------------------");
        subject.dataChange(11F,244,56F);

        // 数据更新,并发送到观察者
        System.out.println("---------------第二次数据更新--------------------------------");
        subject.dataChange(11F,254,568F);

        // 观察者2不订阅了,准备跑路了
        subject.removeObserver(smallWeatherApp);

        //这时数据更新,只会发送给观察者一
        System.out.println("---------------第三次数据更新--------------------------------");
        subject.dataChange(15F,345,134F);
    }
}

执行结果
在这里插入图片描述

Java内置的观察者模式(Observable/Observer)

java在java.util包下提供内置的观察者模式,提供了Observable类和Observer接口分别对应上面的SujectObserver

Observable 定义了addObserverdeleteObservernotifyObserversnotifyObservers等方法,其中有个setChange()方法,只有changed 为true才会通知观察者

改造WeatherData

WeatherData中不需要保存observers,Observable类已经有实现了。修改dataChange方法

 public void dataChange(float temp, float humidity, float pressure){
        this.temp =temp;
        this.humidity =humidity;
        this.pressure =pressure;
        setChanged();
        notifyObservers();
    }

改造WeatherApp

实现java.util包下的Observer接口,修改原来的update方法

@Override
    public void update(Observable obs, Object arg) {
        if (obs instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) obs;
            this.temp = weatherData.getTemp();
            this.humidity = weatherData.getHumidity();
            this.pressure = weatherData.getPressure();
            display();
        }
    }

setChange方法的作用

setChange的作用是便于控制,现实中除非对要求数据非常高,不可能一点数据变动就通知观察者,setChange让你想发送的才放松,这是可以控制的。比如:但温度提高了3°就发送通知。
在这里插入图片描述

使用内置观察者模式存在的问题

首先,细心的人应该会发现,Observable 的通知顺序和上面自定义的是不同的。这样意味着当观察者/可观察者的实现逻辑发生变化,通知次序就发生变化,这样就不符合松耦合了。

其次,Observable 是一个类,而不是接口,这会限制代码的复用潜力,setChange方法是受保护的意味着只有直接继承自Observable,否则你没办法创建Observable实例

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值