需求分析
气象站提供一个WeatgerData类,里面有三个get方法,分别可以取到三个值:温度,湿度,气压。
我们需要实现三个布告板,分别是 “目前状态布告板”,“气象统计布告板”,“天气预告布告板。”
要求
public class WeatherData {//获取温度接口public float getTemperature(){return 0;}//获取湿度接口public float getHumidity(){return 0;}//获取气压接口public float getPressure(){return 0;}//一旦测量数据变化就调用,并且更新三个布告板public void measurementsChanged(){float temperature = getTemperature();float humidity = getHumidity();float pressure = getPressure();//调用更新三个布告板}}
问题
很简单。但是如再新增一个布告板呢?WeatherData就要被修改一次。
现在目的要让布告板与气象站松耦合,并且想象一下假如有上百个布告板,我其中有一个不需要气象站的数据怎么办?
目前气象站是在强行喂饭给布告板啊。
分析
假如weatherData(气象站)是一个出版社,而布告板是订阅该出版社的人。
当出版社每次更新数据时,订阅者就可以收到出版社数据。 并且订阅者有权决定是否允许你给我传递数据。
问题在于,如何让气象站知道哪个布告板订阅了自己。
解决方案
为了解决以上问题,我们在气象站类中采用一个集合来记录订阅者。那么订阅者通过注册的途径来放入集合中。
抽象出主题
根据策略模式,抽象出一个主题接口,专门用来注册订阅者,删除订阅者,修改订阅者(传递改变后的数据给订阅者)
public interface Subject {//注册观察者public void registerObserver(Observer observer);//删除观察者public void removeObserver(Observer observer);//主题状态改变时,通知所有观察者public void notifyObservers();}
抽象出数据
专门用来存放气象站的数据
public class NewData {float temperature;float humidity;float pressure;}
抽象出观察者
抽象出一个订阅者超类,称为观察者。 当气象站的数据改变时,实现该接口的订阅者便会调用update()
public interface Observer {public void update(NewData newData);}
抽象出一个布告板
public interface DisplayElement {public void display();}
重新设计
note : setNewData(NewData newData); 这个方法是气象站数据改变的时候调用的,什么时候改变是气象站决定的,我们不设计,我们只给气象站提供一个外部访问接口。就是它们改变的时候需调用到我们这个接口方法。
weatherData 实现
public class WeatherData implements Subject {private List<Observer> observers;private NewData newData;public WeatherData(){//初始化记录集合observers = new ArrayList();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {int i = observers.indexOf(observer);if(i > 0){observers.remove(i);}}@Overridepublic void notifyObservers() {for(int i = 0; i < observers.size(); i ++){Observer observer = observers.get(i);observer.update(newData);}}public void measurementsChanged(){notifyObservers();}public void setNewData(NewData newData){this.newData = newData;measurementsChanged();}}
布告板实现
布告板实现了观察者接口,展示布告板接口。
刚才说过了,布告板就是订阅气象站数据的订阅者,观察者是订阅者抽象出来的接口。订阅者需要去注册,来表明自己需要气象站的数据。
public class CurrentConditionsDisplay implements Observer, DisplayElement {private NewData newData;private Subject weatherData;public CurrentConditionsDisplay(Subject weatherData){this.weatherData = weatherData;weatherData.registerObserver(this);}@Overridepublic void display() {System.out.println("目前布告板数据是:"+newData);}@Overridepublic void update(NewData newData) {this.newData = newData;}}
测试
public class Test {public static void main(String[] args) {//声明一个气象站WeatherData weatherData = new WeatherData();//声明一个布告板,并且传入气象站,进行注册CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);//新的数据NewData newData = new NewData();//一定newData对象变化,就设置新数据。weatherData.setNewData(newData);}}
小节: 下定义
会发现假如新增一个布告板,我只需要再new一个就好了嘛。 不需要再去进入weatherData类中进行修改了。
目前观察者(订阅者)还是被出版者(气象站) 强行喂饭。 凡是在气象站中注册了的布告板 都会被强行刷新数据。
note: 观察者模式: 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。可以理解为:一个出版社对应多个订阅者。
