16-观察者模式

天气预报需求

具体要求如下:

  • 1)气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)
  • 2)需要设计开放型 API,便于其他第三方也能接入气象站获取数据
  • 3)提供温度、气压和湿度的接口
  • 4)测量数据更新时,要能实时的通知给第三方
    在这里插入图片描述

天气预报需求方案之普通方案

WeatherData类

通过对气象站项目的分析,我们可以初步设计出一个WeatherData类
在这里插入图片描述

  • 1)通过getXxx方法,可以让第三方接入,并得到相关信息
  • 2)当数据有更新时,气象站通过调用dataChange()去更新数据,当第三方再次获取时,就能得到最新数据,当然也可以推送

在这里插入图片描述
CurrentConditions(当前的天气情况)可以理解成是我们气象局的网站

核心代码

气象网站类

/**
 * @ClassName CurrentConditions
 * @author: shouanzh
 * @Description 显示当前的天气情况:可以理解成是气象局的网站
 * @date 2022/1/26 21:12
 */
public class CurrentConditions {
    private Float temperature;
    private Float pressure;
    private Float humidity;

    /**
     * 更新天气情况,通过推送的方式,由 WeatherData 调用
     *
     * @param temperature
     * @param pressure
     * @param humidity
     */
    public void update(Float temperature, Float pressure, Float humidity) {
        // 更新最新天气数据
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        // 展示最新天气数据
        display();
    }

    /**
     * 公告板展示天气情况
     */
    public void display() {
        System.out.println("============最新天气============");
        System.out.println("*** 当前温度:" + this.temperature + " ℃ ***");
        System.out.println("*** 当前气压:" + this.pressure + " kPa ***");
        System.out.println("*** 当前湿度:" + this.humidity + " %RH ***");
    }

}

气象数据类

/**
 * @ClassName WeatherData
 * @author: shouanzh
 * @Description
 *  核心类
 *  1、包含最新的天气信息情况
 *  2、含有 CurrentConditions 对象
 *  3、当数据更新时,主动调用 CurrentConditions 的 update() 方法
 * @date 2022/1/26 21:13
 */
public class WeatherData {

    private Float temperature;
    private Float pressure;
    private Float humidity;
    private CurrentConditions conditions;

    /**
     * 传入 CurrentConditions 对象
     *
     * @param conditions
     */
    public WeatherData(CurrentConditions conditions) {
        this.conditions = conditions;
    }

    public Float getTemperature() {
        return temperature;
    }

    public Float getPressure() {
        return pressure;
    }

    public Float getHumidity() {
        return humidity;
    }

    /**
     * 推送天气数据到网站
     */
    public void dataChange() {
        conditions.update(getTemperature(), getPressure(), getHumidity());
    }

    /**
     * 当天气数据发生变化时进行更新
     *
     * @param temperature
     * @param pressure
     * @param humidity
     */
    public void setData(Float temperature, Float pressure, Float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        dataChange();
    }

}

测试

/**
 * @ClassName client
 * @author: shouanzh
 * @Description Client
 * @date 2022/1/26 21:14
 */
public class Client {

    public static void main(String[] args) {
        // 创建气象网站对象
        CurrentConditions currentConditions = new CurrentConditions();
        // 创建气象数据对象,并传入气象网站对象
        WeatherData weatherData = new WeatherData(currentConditions);
        // 天气发生变化时,更新最新的气象数据
        weatherData.setData(10f, 150f, 40f);
        weatherData.setData(15f, 130f, 60f);
        //weatherData.setData(13f, 160f, 20f);
    }

}

问题分析

  • 1)其他第三方接入气象站获取数据的问题
  • 2)无法在运行时动态的添加第三方(新浪网站)
  • 3)违反OCP原则 => 观察者模式

在WeatherData中增加第三方时,都需要创建对应的第三方公台板对象并加入到dataChange()方法中,既不是动态加入,也不利于维护

观察者模式原理

观察者模式类似订牛奶业务

  • 1)奶站 / 气象局:Subject
  • 2)用户 / 第三方网站:Observer

Subject:登记注册、移除和通知

在这里插入图片描述

  • 1)registerObserver():注册
  • 2)removeObserver():移除
  • 3)notifyObservers():通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送,看具体需求定

Observer:接收输入
在这里插入图片描述
观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化,比如这里的奶站是Subject,是1的一方。用户是Observer,是多的一方。

天气预报需求方案之观察者模式

UML类图
在这里插入图片描述

核心代码

观察者对象Observer

/**
 * @ClassName Observer
 * @author: shouanzh
 * @Description 观察者接口
 * @date 2022/1/26 22:12
 */
public interface Observer {

    void update(Float temperature, Float pressure, Float humidity);

}

/**
 * @ClassName CurrentConditions
 * @author: shouanzh
 * @Description 观察者实现
 * @date 2022/1/26 22:19
 */
public class CurrentConditions implements Observer{

    private Float temperature;
    private Float pressure;
    private Float humidity;


    @Override
    public void update(Float temperature, Float pressure, Float humidity) {
        // 更新最新天气数据
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        // 展示最新天气数据
        display();
    }

    /**
     * 公告板展示天气情况
     */
    public void display() {
        System.out.println("============最新天气============");
        System.out.println("*** 当前温度:" + this.temperature + " ℃ ***");
        System.out.println("*** 当前气压:" + this.pressure + " kPa ***");
        System.out.println("*** 当前湿度:" + this.humidity + " %RH ***");
    }
}

主体对象Subject

/**
 * @ClassName Subject
 * @author: shouanzh
 * @Description 主体对象接口
 * @date 2022/1/26 22:11
 */
public interface Subject {

    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers();

}

/**
 * @ClassName WeatherData
 * @author: shouanzh
 * @Description 主体对象实现
 * @date 2022/1/26 22:14
 */
public class WeatherData implements Subject{

    private Float temperature;
    private Float pressure;
    private Float humidity;
    private final List<Observer> observerList;

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

    public Float getTemperature() {
        return temperature;
    }

    public Float getPressure() {
        return pressure;
    }

    public Float getHumidity() {
        return humidity;
    }

    /**
     * 推送天气数据到网站
     */
    public void dataChange() {
        notifyObservers();
    }

    /**
     * 当天气数据发生变化时进行更新
     *
     * @param temperature
     * @param pressure
     * @param humidity
     */
    public void setData(Float temperature, Float pressure, Float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        dataChange();
    }


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

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

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

测试

/**
 * @ClassName Client
 * @author: shouanzh
 * @Description Client
 * @date 2022/1/26 22:21
 */
public class Client {

    public static void main(String[] args) {
        // 创建气象网站对象
        CurrentConditions currentConditions = new CurrentConditions();
        // 创建气象数据对象
        WeatherData weatherData = new WeatherData();
        // 注册气象网站对象
        weatherData.registerObserver(currentConditions);
        // 天气发生变化时,更新最新的气象数据
        weatherData.setData(10f, 150f, 40f);
        //============最新天气============
        //*** 当前温度:10.0 ℃ ***
        //*** 当前气压:150.0 kPa ***
        //*** 当前湿度:40.0 %RH ***
    }

观察者模式的好处

  • 1)观察者模式设计后,会以集合的方式来管理用户Observer,包括注册、移除和通知
  • 2)这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类WeatherData不会修改代码,遵守了ocp原则

例如,我们新增SinaWebSite和BaiDuWebSite两个三方网站,接口气象局。此时三方只需实现相应接口即可,WeatherData不需要有任何的改变

/**
 * @ClassName SinaWebSite
 * @author: shouanzh
 * @Description 观察者实现
 * @date 2022/1/26 22:19
 */
public class SinaWebSite implements Observer {
    private Float temperature;
    private Float pressure;
    private Float humidity;

    /**
     * 更新天气情况,通过推送的方式,由 WeatherData 调用
     *
     * @param temperature
     * @param pressure
     * @param humidity
     */
    @Override
    public void update(Float temperature, Float pressure, Float humidity) {
        // 更新最新天气数据
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        // 展示最新天气数据
        display();
    }

    /**
     * 公告板展示天气情况
     */
    public void display() {
        System.out.println("============新浪网-最新天气============");
        System.out.println("*** 新浪网-当前温度:" + this.temperature + " ℃ ***");
        System.out.println("*** 新浪网-当前气压:" + this.pressure + " kPa ***");
        System.out.println("*** 新浪网-当前湿度:" + this.humidity + " %RH ***");
    }
}

测试

/**
 * @ClassName Client
 * @author: shouanzh
 * @Description Client
 * @date 2022/1/26 22:21
 */
public class Client {

    public static void main(String[] args) {
        // 创建气象网站对象
        CurrentConditions currentConditions = new CurrentConditions();
        // 创建气象数据对象
        WeatherData weatherData = new WeatherData();
        // 注册气象网站对象
        weatherData.registerObserver(currentConditions);
        weatherData.registerObserver(new SinaWebSite());
        // 天气发生变化时,更新最新的气象数据
        weatherData.setData(10f, 150f, 40f);
        //============最新天气============
        //*** 当前温度:10.0 ℃ ***
        //*** 当前气压:150.0 kPa ***
        //*** 当前湿度:40.0 %RH ***
        //============新浪网-最新天气============
        //*** 新浪网-当前温度:10.0 ℃ ***
        //*** 新浪网-当前气压:150.0 kPa ***
        //*** 新浪网-当前湿度:40.0 %RH ***
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值