需求分析

气象站提供一个WeatgerData类,里面有三个get方法,分别可以取到三个值:温度,湿度,气压。

 

我们需要实现三个布告板,分别是 “目前状态布告板”,“气象统计布告板”,“天气预告布告板。”

 

要求:

1、三个布告板都会用到气象站提供的数据。

2、并且一旦气象站数据发生变化,布告板上的数据也必须跟着变化。

3、布告板可以随心所欲的删除,或者添加新的布告板。

 

 

第一次设计:最“简单”的设计



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();
}


 

第二次设计

气象站实现了主题接口。并且实现了三个方法,注册观察者(订阅者)、删除、以及更新数据。

不要迷惑的地方:

setNewData(NewData newData); 这个方法是气象站数据改变的时候调用的,什么时候改变是气象站决定的,我们不设计,我们只给气象站提供一个外部访问接口。就是它们改变的时候需调用到我们这个接口方法。



public class WeatherData implements Subject {

private List<Observer> observers;
private NewData newData;

public WeatherData(){
//初始化记录集合
observers = new ArrayList();
}


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

@Override
public void removeObserver(Observer observer) {
int i = observers.indexOf(observer);
if(i > 0){
observers.remove(i);
}
}

@Override
public 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);
}

@Override
public void display() {
System.out.println("目前布告板数据是:"+newData);
}

@Override
public 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类中进行修改了。

目前观察者(订阅者)还是被出版者(气象站) 强行喂饭。  凡是在气象站中注册了的布告板 都会被强行刷新数据。

 

 

 

 

 

定义观察者模式

定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。

可以理解为:一个出版社对应多个订阅者。

 


作者:​​无上仰无​​​,转载请注明原文链接