设计模式之观察者模式

目录

一、案例demo

1、需求

2、设计分析

 3、WeatherData 类

二、直接代码耦合的方案

三、使用观察者模式

3.1、观察者模式下气象站类图设计

 3.2、手动实现观察者模式( 气象站设计 )

四、使用Java内置的观察者模式( 气象站设计 )

4.1、用法


一、案例demo

1、需求

        建立一个气象观测站,并且这个气象观测站暂时有三种布告板,分别显示:目前的状况、气象统计、简单的预报。当 WeatherObject对象获得最新的测量数据时,三种布告板必须实时更新。

        气象观测站对应 WeatherData 对象,WeatherData 对象负责追踪目前的天气状况(温度、湿度、气压)。

2、设计分析

该系统分为三个部分:

  • 气象站:获取实际气象数据的物理装置
  • WeatherData 对象:追踪来自气象站的数据,并更新布告板
  • 布告板:显示目前天气状况,给用户显示

在这里插入图片描述

 3、WeatherData 类

在这里插入图片描述


二、直接代码耦合的方案

 直接在WeatherData 类中的 measurementsChanged()方法编写气象数据更新逻辑。

在这里插入图片描述

问题: 针对具体实现编程,后门面如果需要对布告板进行增删操作时,就必须要修改程序。


三、使用观察者模式

观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新 

设计原则:为了交互对象之间的松耦合设计而努力 

图解:

在这里插入图片描述

在这里插入图片描述

3.1、观察者模式下气象站类图设计

在这里插入图片描述

 3.2、手动实现观察者模式( 气象站设计 )

主题接口:

package com.kgf.headFirst.observer.customer;

/**
 * 主题接口
 * @author kgf
 * @date 2023/6/11 15:10
 */
public interface Subject {

    // 注册方法,接收一个观察者类型的参数
    public void registerObserver(Observer observer);

    // 移除方法,接收一个观察者类型的参数
    public void removeObserver(Observer observer);

    // 通知方法
    public void notifyObservers();

}

主题实现类:

package com.kgf.headFirst.observer.customer;

import java.util.ArrayList;
import java.util.List;

/**
 * 主题的实现类
 * @author kgf
 * @date 2023/6/11 15:13
 */
public class WeatherData implements Subject{

    // ArrayList 用来记录观察者,在构造器中初始化
    private List<Observer> observers;

    private float temperature;

    private float humidity;

    private float pressure;

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

    /***
     * 注册观察者时,只需加到ArrayList后面即可
     * @param observer
     */
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    /***
     * 删除观察者,只需从ArrayList中移除
     * @param observer
     */
    @Override
    public void removeObserver(Observer observer) {
        int i = observers.indexOf(observer);
        if (i >= 0){
            observers.remove(i);
        }
    }

    /***
     * 此方法把主题的状态通知每个观察者
     */
    @Override
    public void notifyObservers() {
        for (Object o : observers) {
            Observer observer = (Observer) o;
            observer.update(temperature, humidity, pressure);
        }
    }

    // 当从气象站得到更新观测值时,通知观察者
    public void measurementsChanged(){
        notifyObservers();
    }

    // 测试方法
    public void setMeasurements(float temperature,float humidity,float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}

观察者接口:

package com.kgf.headFirst.observer.customer;

/**
 * 定义一个观察者接口
 * @author kgf
 * @date 2023/6/11 15:11
 */
public interface Observer {

    /***
     * 更新数据,当气象观测值改变时,主题会把这些状态值作为此方法的参数传递给观察者
     * @param temp:温度
     * @param humidity:湿度
     * @param pressure:气压
     */
    public void update(float temp,float humidity,float pressure);

}

布告板接口:

package com.kgf.headFirst.observer.customer;

/**
 * 布告板接口
 * @author kgf
 * @date 2023/6/11 15:18
 */
public interface DisplayElement {

    /***
     * 布告板显示数据时,调用此方法
     */
    public void display();

}

布告板(订阅者)具体实现类:

package com.kgf.headFirst.observer.customer;

/**
 * 布告板的实现类
 * @author kgf
 * @date 2023/6/11 15:19
 */
public class CurrentConditionsDisplay implements Observer,DisplayElement{

    private float temperature;

    private float humidity;

    private Subject weatherData;

    /***
     * 构造器需要weatherData对象(主题)作为注册之用
     * @param weatherData
     */
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("温度:" + temperature + ";" + "湿度:" + humidity);
    }

    /***
     * 当update()被调用时,保存温度和湿度数据,然后调用display()显示数据
     * @param temp:温度
     * @param humidity:湿度
     * @param pressure:气压
     */
    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);

        weatherData.setMeasurements(80,65,30.4f);
    }
}

四、使用Java内置的观察者模式( 气象站设计 )

在这里插入图片描述

4.1、用法

对象变成观察者: 实现观察者接口(java.util.Observer),然后调用Observer对象的 addObserver()方法。取消观察者时,调用 deleteObserver()方法即可。

主题如何给观察者(订阅者)发送通知
使用Observable(java.util.Observable)类,然后:

  • 调用 setChanged()方法,标记状态已经改变的情况
  • 调用两种 notifyObservers()方法中的 notifyObservers()或 notifyObservers(Obiect arg)中的任意一个方法

观察者(订阅者)如何接收通知:
观察者实现了更新的方法:update(Observable o,Object arg)

  • Observable:把主题作为参数,方便让观察者知道是哪个主题通知的
  • Object :传入notifyObservers()的数据对象,没有则说明为空

主题如果想推(push)数据给观察者,可以把数据当为数据对象传送给notifyObservers(Obiect arg)方法。否则,观察者就必须从主题中拉(pull)数据。

WeatherData 类:

package com.kgf.headFirst.observer.buildin;

import java.util.Observable;

/**
 * 主题的实现类
 * @author kgf
 * @date 2023/6/11 15:13
 */
public class WeatherData extends Observable {

    private float temperature;

    private float humidity;

    private float pressure;

    public WeatherData() {

    }

    /***
     * 当从气象站得到更新观测值时,通知观察者
     */
    public void measurementsChanged(){
        //标记数据状态已经改变
        setChanged();
        //通知观察者
        notifyObservers();
    }

    // 测试方法
    public void setMeasurements(float temperature,float humidity,float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}

CurrentConditionsDisplay 布告板(订阅者)具体实现类:

package com.kgf.headFirst.observer.buildin;

import com.kgf.headFirst.observer.customer.DisplayElement;
import java.util.Observable;
import java.util.Observer;

/**
 * 布告板的实现类
 * @author kgf
 * @date 2023/6/11 15:19
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement {

    private float temperature;

    private float humidity;

    private Observable observable;

    /***
     * 构造器需要weatherData对象(主题)作为注册之用
     * @param observable
     */
    public CurrentConditionsDisplay(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }

    @Override
    public void display() {
        System.out.println("温度:" + temperature + ";" + "湿度:" + humidity);
    }


    @Override
    public void update(Observable o, Object arg) {
        if (observable instanceof WeatherData){
            WeatherData weatherData = (WeatherData) observable;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            display();
        }
    }

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(80,65,30.4f);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值