设计模式学习--观察者模式(Observer Pattern)

确定这两个对象之间的关系:


主题对象管理某些数据,一旦数据发生改变,会主动向观察者进行通知,然而观察者不必向主题进行索取。

主题并不知道具体的观察者是谁,这是它们之间的关系。

以上涉及到的设计原则:


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

具体实例:气象站的实现

1. 定义一个主题接口Subject

package observerPattern;

/**

  • 主题接口

  • @author wwj

*/

public interface Subject {

public void registerObserver(Observer o); //这两个方法都需要一个观察者作为变量,该观察者是用那个来注册和删除的

public void removeObserver(Observer o);

public void notifyObserver(); //当主题状态发生改变时,这个方法会被调用,以通知所有的观察者

}

2. 定义一个观察者接口Observer

package observerPattern;

/**

  • 观察者接口

  • @author wwj

*/

public interface Observer {

public void update(float temp, float humidity, float pressure);

}

3. 定义一般气象布告板接口DisplayElement

package observerPattern;

/**

  • 公告板接口

  • @author wwj

*/

public interface DisplayElement {

public void display();

}

4. 定义主题类:WeatherData实现接口

package observerPattern;

import java.util.ArrayList;

/**

  • WeatherData实现了Subject接口

  • @author wwj

*/

public class WeatherData implements Subject {

private ArrayList observers; //用于记录观察者

private float temperature; //温度

private float humidity; //湿度

private float pressure; //压力

public WeatherData() {

observers = new ArrayList();

}

@Override

public void registerObserver(Observer o) {

observers.add(o);

}

@Override

public void removeObserver(Observer o) {

int i = observers.indexOf(o);

if(i >= 0) {

observers.remove(i);

}

}

@Override

public void notifyObserver() {

for(int i = 0; i < observers.size(); i++) {

Observer observer = (Observer)observers.get(i);

observer.update(temperature, humidity, pressure);

}

}

public void measurementsChanged() {

notifyObserver();

}

public void setMeasurements(float temperature, float humidity, float pressure) {

this.temperature = temperature;

this.humidity = humidity;

this.pressure = pressure;

measurementsChanged();

}

}

5. 定义四个布告板类实现观察者接口和布告板接口

package observerPattern;

/**

  • 观察者类实现观察者接口和显示板接口

  • @author wwj

*/

public class CurrentConditionDisplay implements Observer, DisplayElement {

private float temperature;

private float humidity;

private Subject weathderData;

public CurrentConditionDisplay(Subject weathderData) {

this.weathderData = weathderData;

weathderData.registerObserver(this); //注册

}

@Override

public void display() {

System.out.println("Current coditions: " + temperature + "F degress and " + humidity + “% humidity”);

}

@Override

public void update(float temp, float humidity, float pressure) {

this.temperature = temp;

this.humidity = humidity;

display();

}

}

package observerPattern;

/**

  • 天气统计布告板

  • @author wwj

*/

public class StatisticsDisplay implements Observer, DisplayElement {

private float maxTemp = 0.0f;; //最大温度

private float minTemp = 200; //最小温度

private float tempSum = 0.0f; //统计温度和

private int numReadings; //统计温度次数

private WeatherData weatherData;

public StatisticsDisplay(WeatherData weatherData) {

this.weatherData = weatherData;

weatherData.registerObserver(this);

}

@Override

public void display() {

System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + “/” + maxTemp + “/” + minTemp);

}

@Override

public void update(float temp, float humidity, float pressure) {

tempSum += temp;

numReadings++;

if(temp > maxTemp) {

maxTemp = temp;

}

if(temp < minTemp) {

minTemp = temp;

}

display();

}

}

package observerPattern;

/**

  • 天气预报布告板

  • @author wwj

*/

public class ForecastDisplay implements Observer, DisplayElement {

private float currentPressure = 29.92f; //当前气压

private float lastPressure; //以往气压

private WeatherData weatherData;

public ForecastDisplay(WeatherData weatherData) {

this.weatherData = weatherData;

weatherData.registerObserver(this);

}

@Override

public void display() {

System.out.println(“Forcast:”);

if(currentPressure > lastPressure) {

System.out.println(“Improving weather on the way!”);

} else if(currentPressure == lastPressure) {

System.out.println(“more of the same”);

} else if(currentPressure < lastPressure) {

System.out.println(“Watch out for cooler, rainy weather”);

}

}

@Override

public void update(float temp, float humidity, float pressure) {

lastPressure = currentPressure;

currentPressure = pressure;

display();

}

}

package observerPattern;

/**

  • 酷热指数布告板

  • @author wwj

  • 注:那个计算酷热指数的公式不必深究

*/

public class HeatIndexDisplay implements Observer, DisplayElement {

float heatIndex = 0.0f;

private WeatherData weatherData;

public HeatIndexDisplay(WeatherData weatherData) {

this.weatherData = weatherData;

weatherData.registerObserver(this);

}

public void update(float t, float rh, float pressure) {

heatIndex = computeHeatIndex(t, rh);

display();

}

private float computeHeatIndex(float t, float rh) {

float index = (float)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh)

  • (0.00941695 * (t * t)) + (0.00728898 * (rh * rh))

  • (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +

(0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 *

(rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) +

(0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +

0.000000000843296 * (t * t * rh * rh * rh)) -

(0.0000000000481975 * (t * t * t * rh * rh * rh)));

return index;

}

public void display() {

System.out.println("Heat index is " + heatIndex);

}

}

6. 来吧,开始测试

package observerPattern;

/**

  • 测试类

  • @author wwj

*/

public class WeatherStation {

public static void main(String[] args) {

//建立一个WeatherData对象

WeatherData weatherData = new WeatherData();

//第一个布告板

CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(

weatherData);

StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);

ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);

HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData);

// 模拟新的气象数据

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

weatherData.setMeasurements(82, 70, 29.2f);

weatherData.setMeasurements(78, 90, 29.2f);

}

}

7. 测试结果:

Current coditions: 80.0F degress and 65.0% humidity

Avg/Max/Min temperature = 80.0/80.0/80.0

Forcast:

Improving weather on the way!

Heat index is 82.95535

Current coditions: 82.0F degress and 70.0% humidity

Avg/Max/Min temperature = 81.0/82.0/80.0

Forcast:

Watch out for cooler, rainy weather

Heat index is 86.90124

Current coditions: 78.0F degress and 90.0% humidity

Avg/Max/Min temperature = 80.0/82.0/78.0

Forcast:

more of the same

Heat index is 83.64967

以上的观察者模式实现是通过主题以“推”的方式通知观察者们,观察者可以在一次通知中一口气得到所有东西。

因为观察者与主题发生了争吵,观察者有自己的想法,希望能“拉”走主题的状态,然而Java内置的Observer模式就支持这样,下面来看看吧。

1. 继承Observable类的WeatherData(不再需要自定义接口了,但这样真的好吗?)

package weatherObservable;

import java.util.Observable;

/**

  • 使用Java内置的观察者模式

  • @author wwj

*/

public class WeatherData extends Observable {

private float temperature;

private float humidity;

private float pressure;

/**

  • 我们的构造器不再需要为了记住观察者们而建立数据结构了

*/

public WeatherData(){}

public void measurementsChanged() {

setChanged(); //Observable类方法

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;

}

}

2. 4个布告板中的代码稍微发生了点变化

package weatherObservable;

import java.util.Observable;

import java.util.Observer;

/**

  • 实现Java内置的观察者接口,布告板不变

  • @author wwj

*/

public class CurrentConditionDisplay implements Observer, DisplayElement{

Observable observable;

private float temperature;

private float humidity;

public CurrentConditionDisplay(Observable observable) {

this.observable = observable;

observable.addObserver(this); //登记为观察者

}

最后送福利了,现在关注我可以获取包含源码解析,自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿

录播视频图.png

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

mport java.util.Observable;

import java.util.Observer;

/**

  • 实现Java内置的观察者接口,布告板不变

  • @author wwj

*/

public class CurrentConditionDisplay implements Observer, DisplayElement{

Observable observable;

private float temperature;

private float humidity;

public CurrentConditionDisplay(Observable observable) {

this.observable = observable;

observable.addObserver(this); //登记为观察者

}

最后送福利了,现在关注我可以获取包含源码解析,自定义View,动画实现,架构分享等。
内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,有flutter—底层开发—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿

[外链图片转存中…(img-YTxxu4Aw-1714693357072)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值