目的:用WeatherData对象从气象台取得数据并更新布告板,考虑系统的可扩展性,满足随心所欲添加或删除布告板。如图所示:
考虑在同一时刻只选择一个布告板并显示的情况。抽取中其中改变的部分,即布告板。设想实现如下图:
上图设计中可以满足弹性的任意选择一个布告板并对其进行更新。然而我们需要的是有多个布告板能显示不同的
内容并显示更新。解决问题的方法:WeatherData中需要有一个容器来缓存多个布告板,但是并不是所有的布告
板都需要进行更新显示。WeatherData只对那些有需要更新并显示的布告板进行通知并更新他们。所以引出了观察
者模式,这相当于一个订阅问题,每个布告板都是一个观察者,Weather是一个主题。观察者对主题感兴趣则对主题
进行订阅。当观察者对主题不再感兴趣时者取消订阅主题,即做到了任意添加或删除布告板。当主题改变时,所有订
阅主题的观察者都将被通知。
实现图如下:
实现代码:
主题接口:
public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); }
观察者接口:
public interface Observer { public void update(float temperature,float pressure,float humidy); public void register(Subject weatherData); public void cancel(); }
显示接口:
public interface DisplayElement { public void display(); }
WeatherData类:
public class WeatherData implements Subject{ private float temperature; private float pressure; private float humidy; private List observers; public WeatherData(){ observers=new ArrayList(); } @Override public void registerObserver(Observer o) { // TODO Auto-generated method stub observers.add(o); } @Override public void removeObserver(Observer o) { // TODO Auto-generated method stub observers.remove(o); } @Override public void notifyObservers() { // TODO Auto-generated method stub for(int i=0;i<observers.size();i++) { Observer o=(Observer)observers.get(i); o.update(temperature,pressure,humidy); } } public void measurementsChanged() { notifyObservers(); } public void setMeasurements(float temperature,float pressure,float humidy) { this.temperature=temperature; this.pressure=pressure; this.humidy=humidy; measurementsChanged(); } }
布告板1:
public class CurrentConditionDisplay implements Observer, DisplayElement{ private float temperature; private float pressure; private float humidy; private Subject weatherData; public CurrentConditionDisplay() {} public CurrentConditionDisplay(Subject weatherData) { this.weatherData=weatherData; weatherData.registerObserver(this); } @Override public void display() { // TODO Auto-generated method stub System.out.println("Current conditions: "); System.out.println(temperature+"F degrees"); System.out.println(pressure+"%pressure"); System.out.println(humidy+"%humidy"); } @Override public void update(float temperature,float pressure,float humidy) { // TODO Auto-generated method stub this.temperature=temperature; this.pressure=pressure; this.humidy=humidy; display(); } @Override public void register(Subject weatherData) { // TODO Auto-generated method stub this.weatherData=weatherData; weatherData.registerObserver(this); } @Override public void cancel() { // TODO Auto-generated method stub weatherData.removeObserver(this); } }
布告板2:
public class AverageConditionDisplay implements Observer,DisplayElement{ private float temperature; private float pressure; private float humidy; Subject weatherData; public AverageConditionDisplay() {} public AverageConditionDisplay(Subject weatherData) { this.weatherData=weatherData; weatherData.registerObserver(this); } @Override public void display() { // TODO Auto-generated method stub System.out.println("average conditions: "); System.out.println(temperature+"F degrees"); System.out.println(pressure+"%pressure"); System.out.println(humidy+"%humidy"); } @Override public void update(float temperature, float pressure, float humidy) { // TODO Auto-generated method stub if(this.temperature==0) { this.temperature=temperature; } else { this.temperature=(this.temperature+temperature) / 2; } if(this.pressure==0) { this.pressure=pressure; } else { this.pressure=(this.pressure+pressure) / 2; } if(this.humidy==0) { this.humidy=humidy; } else { this.humidy=(this.humidy+humidy) / 2; } display(); } @Override public void register(Subject weatherData) { // TODO Auto-generated method stub this.weatherData=weatherData; weatherData.registerObserver(this); } @Override public void cancel() { // TODO Auto-generated method stub weatherData.removeObserver(this); } }
气象模拟类:
public class WeatherStation { public static void main(String [] args) { WeatherData weatherData=new WeatherData(); //CurrentConditionDisplay ccd=new CurrentConditionDisplay(weatherData); //AverageConditionDisplay acd=new AverageConditionDisplay(weatherData); CurrentConditionDisplay ccd=new CurrentConditionDisplay(); ccd.register(weatherData); AverageConditionDisplay acd=new AverageConditionDisplay(); acd.register(weatherData); weatherData.setMeasurements(80, 30.4f, 65); weatherData.setMeasurements(60, 28.2f, 35); //weatherData.removeObserver(acd); acd.cancel(); weatherData.setMeasurements(90, 32.4f, 62); } }