【HeadFirst设计模式】观察者模式

本文深入解析观察者模式,探讨其如何实现对象间的一对多依赖,确保当一个对象状态改变时,所有依赖对象能自动更新。通过具体实例,如WeatherData对象与多个布告板的互动,展示了模式的应用及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

懒得写了,转一个

  • 出版者改称为“主题”(Subject),订阅者改称为“观察者”(Observer)。 出版者+订阅者=观察者模式
  • 观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
  • 设计原则:为了交互对象之间的松耦合设计而努力。

 

作者:Grey

原文地址:http://www.cnblogs.com/greyzeng/p/5918205.html

模式名称

观察者模式(Observer Pattern)

需求

我们要通过WeatherData对象从物理气象站获取温度,湿度,气压数据,并且更新三个布告板的信息:

  • 目前状况(温度,湿度,气压)
  • 气象统计
  • 天气预报

解决方案

WeatherData类中,我们可以通过以下三个方法来获取测量值:

getTemperature() // 获取温度
getHumidity() // 获取湿度
getPressure() // 获取气压

当新的测量数据准备好以后,

measurementsChanged()

方法被调用

然后我们就可以更新三个布告板的数据了。

更多地,我们需要满足可扩展的要求,可以方便添加/删除布告板

一种实现:

public class WeatherData {
    public void measurementsChanged() {
        float temperature = getTemperature(); // 获取温度
        float humidity =  getHumidity() // 获取湿度
        float pressure = getPressure() // 获取气压
        currentConditionsDisplay.update(temperature, humidity, pressure); // 更新“目前状况”布告板
        statisticsDisplay.update(temperature, humidity, pressure); // 更新“气象统计”布告板
        forecastDisplay.update(temperature, humidity, pressure); // 更新“天气预报”布告板
    }
}

这个模型类似于出版者和订阅者的关系,出版者发布了主题(气压,湿度,温度),订阅者订阅这些主题,等这些主题有新的内容的时候,会自动推送给订阅了这个主题的订阅者这里,这就是观察者模式,其中出版者被称为“主题”(Subject),订阅者被称为“观察者”(Observer)。

public interface Observer {
    // 观察者根据传入的参数进行更新操作。
    public void update(temperature, humidity, pressure); 
}
public interface Subject {
    void registerObserver(Observer o); // 注册观察者
    void removeObserver(Observer o); // 移除观察者
    void notifyObservers(); // 主题变化后,通知观察者
}

WeatherData需要实现主题接口

public class WeatherData implements Subject {
    private ArrayList<Observer> observers; // 用来装需要订阅这个主题的观察者
    private float temperature;
    private float humidity;
    private float pressure;
    WeatherData() {
        observers = new ArrayList<>();
    }
    @Override
    public void registerObserver(Observer o) {
        observers.add(o); // 订阅

    }

    @Override
    public void removeObserver(Observer o) {
        if (null == observers || 0 == observers.size()) {
            System.out.println("observers is null");
        } else {
            int i = observers.indexOf(o);
            if (i >= 0) {
                observers.remove(i); // 取消订阅
            }
        }
    }

    @Override
    public void notifyObservers() {
        if (null == observers || 0 == observers.size()) {
            System.out.println("observers is null");
        } else {
            for (Observer observer : observers) {
                observer.update(temperature, humidity, pressure); // 更新每个观察者的状态
            }
        }
    }

    
    public void setMeasurements(float temperature, float humidity, float pressure) {
        // 当我们调用setMeasurements()方法的时候,就获取最新的数据并通知每个观察者。
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers();
    }

}

每个布告板作为观察者,需要实现Observer接口,以“当前状态”布告板为例:

public class CurrentConditionsDisplay implements Observer{
    private float temperature;
    private float humidity;
    CurrentConditionsDisplay(Subject weatherData) {
        weatherData.registerObserver(this);
    }
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        System.out.println("update CurrentConditionDisplay,humidity:"+humidity+" temperature:"+temperature);
    }
}

类似地,我们可以得到其余布告板,比如天气预报布告板:ForecastDisplay,

public class ForecastDisplay implements Observer{
    private float temperature;
    private float humidity;
    private float pressure;
    ForecastDisplay(Subject weatherData) {
        weatherData.registerObserver(this);
    }
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        System.out.println("update CurrentConditionDisplay,humidity:" + humidity + " temperature:" + temperature + " pressure:" + pressure);
    }
}

测试代码:

public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(83,3,33);
        weatherData.setMeasurements(23,45,48);
        weatherData.setMeasurements(4,6,8);

        new ForecastDisplay(weatherData);
        weatherData.setMeasurements(1,2,3);
    }
}

输出结果:

update CurrentConditionDisplay,humidity:3.0 temperature:83.0
update CurrentConditionDisplay,humidity:45.0 temperature:23.0
update CurrentConditionDisplay,humidity:6.0 temperature:4.0
update CurrentConditionDisplay,humidity:2.0 temperature:1.0
update CurrentConditionDisplay,humidity:2.0 temperature:1.0 pressure:3.0

JDK中内置的观察者模式

java.util.Observable;
java.util.Observer;

这两个类和我们之前讨论的SubjectObserver类似,

java.util.Observable中提供了:

setChanged(); // 表明状态已经改变
notifyObservers(); // 通知所有观察者
addObserver(Observer o); // 增加观察者

java.util.Observer中提供了:

update(); // 更新订阅信息

采用JDK内置的观察者模式修改后的WeatherData

public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;
    WeatherData() {
    }


    private void measurementsChanged() {
        setChanged();
        notifyObservers();
    }
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
    float getTemperature() {
        return temperature;
    }
    float getHumidity() {
        return humidity;
    }
    float getPressure() {
        return pressure;
    }

}

CurrentConditionsDisplay

public class CurrentConditionsDisplay implements Observer{
    private float temperature;
    private float humidity;
    CurrentConditionsDisplay(Observable observable) {
        observable.addObserver(this);
    }


    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData)o;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            System.out.println("update CurrentConditionDisplay,humidity:"+humidity+" temperature:"+temperature);
        }
    }
}

测试代码:

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(83,3,33);
        weatherData.setMeasurements(23,45,48);
        weatherData.setMeasurements(4,6,8);
    }
}

输出结果:

update CurrentConditionDisplay,humidity:3.0 temperature:83.0
update CurrentConditionDisplay,humidity:45.0 temperature:23.0
update CurrentConditionDisplay,humidity:6.0 temperature:4.0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值