在上文:深入浅出设计模式二——WeatherData设计(观察者模式)实现一
我们利用了自己缩写的Subject和Observer类完成了天气预报系统。
在JAVA API中已有写好的观察者模式供我们使用,本文将利用它们重新写一个天气预报系统。
在java.util包中有两个类可观察者Observable和观察者Observer。分别相当于Subject类和Observer类。
在Observable类中已经实现了addObserver,deleteObserver,notifyObservers方法,需要注意的是notifyObservers调用前需要调用setChanged标志状态改变,如果要清除状态改变标志则调用clearChanged方法。
UML图如下:
代码如下:
package com.lwf.disign.learn.observer.weatherdata2; import java.util.Observable; public class WeatherData extends Observable{ private float temperature; private float humidity; private float pressure; public WeatherData(){} public float getTemprature(){ return temperature; } public float getHumidity(){ return humidity; } public float getPressure(){ return pressure; } public void measurementsChanged(){ setChanged(); notifyObservers(); } public void setMeasurements(float temperature,float humidity,float pressure){ this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }
package com.lwf.disign.learn.observer.weatherdata2; import java.util.Observable; import java.util.Observer; public class CurrentConditionsDisplay implements Observer { Observable observable; private float temperature; private float humidity; private float pressure; public CurrentConditionsDisplay(Observable observable){ this.observable = observable; observable.addObserver(this); } public void update(Observable obs,Object arg) { if (obs instanceof WeatherData) { WeatherData weatherData = (WeatherData)obs; this.temperature = weatherData.getTemprature(); this.humidity = weatherData.getHumidity(); this.pressure = weatherData.getPressure(); display(); } } public void display() { System.out.println("Temperature:" + temperature + " Humidity:" + humidity + " Pressure:" + pressure); } }
测试类:
package com.lwf.disign.learn.observer.weatherdata2; public class WeatherDataTest { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay o1 = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(12, 23, 24); weatherData.setMeasurements(42, 55, 77); weatherData.setMeasurements(43, 55, 77); weatherData.setMeasurements(44, 55, 77); weatherData.setMeasurements(45, 55, 77); weatherData.setMeasurements(46, 55, 77); } }
输出结果为:
Temperature:12.0 Humidity:23.0 Pressure:24.0 Temperature:42.0 Humidity:55.0 Pressure:77.0 Temperature:43.0 Humidity:55.0 Pressure:77.0 Temperature:44.0 Humidity:55.0 Pressure:77.0 Temperature:45.0 Humidity:55.0 Pressure:77.0 Temperature:46.0 Humidity:55.0 Pressure:77.0
附件有代码文件。
关注变化:
我们看到JAVA内置的Observer模式的实现,它的Observable是一个类而不是一个接口,那么这个设计违背了面向接口编程,而不是面向实现编程的原则。所以如果当你需要从多个类继承的时候那么就不能使用Observale了。所以如果那种情况的话只能象weatherData的第一个实现一样,自己定义一个Subject接口。
其它JAVA类库使用观察者模式的情况
在JAVA SWING中使用的事件模型,给按钮添加事件的行为即是观察者模式。如下例:
package com.lwf.disign.learn.observer.weatherdata2; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class SwingObserverExample { JFrame frame; public static void main(String[] args) { SwingObserverExample s = new SwingObserverExample(); s.go(); } public void go(){ frame = new JFrame(); JButton button = new JButton("should i do"); button.addActionListener(new AngleListener()); button.addActionListener(new DeviListener()); frame.getContentPane().add(BorderLayout.CENTER,button); frame.setVisible(true); } class AngleListener implements ActionListener{ public void actionPerformed(ActionEvent e) { System.out.println("anglelistener"); } } class DeviListener implements ActionListener{ public void actionPerformed(ActionEvent e) { System.out.println("deviListener"); } } }
按钮通过addActionListener把每个观察者加入观察列表。一旦状态发生改变,则触发事件。