观察者模式
观察者模式:定义了对象之间的一对多依赖,这样当一个对象改变状态是,它的所有依赖者都会收到通知并自动更新。
观察者模式提供了一种对象设计,让主题和观察者之间松耦合,Android中的事件机制是典型的观察者模式。
两种实现方式:1、自定义主题和观察者接口;2、使用Java内置观察者模式支持。
举例1:(自定义接口)
定义subject和observer接口:
1 package com.nwpulisz.observerpattren; 2 public interface Subject { 3 public void registerObserver(Observer o); 4 public void removeObserver(Observer o); 5 public void notifyObservers(); 6 }
1 package com.nwpulisz.observerpattren; 2 public interface Observer { 3 public void update(float temp,float humidity,float pressure); 4 }
定义display接口,用于显示相应的内容:
1 package com.nwpulisz.observerpattren; 2 public interface Display { 3 public void display(); 4 }
定义一个主题类,继承subject接口:
1 package com.nwpulisz.observerpattren; 2 import java.util.ArrayList; 3 public class WeatherData implements Subject { 4 private ArrayList observers; 5 private float temperature; 6 private float humidity; 7 private float pressure; 8 public WeatherData(){ 9 observers = new ArrayList(); 10 } 11 @Override 12 public void registerObserver(Observer o) { 13 // TODO Auto-generated method stub 14 observers.add(o); 15 } 16 @Override 17 public void removeObserver(Observer o) { 18 // TODO Auto-generated method stub 19 int i = observers.indexOf(o); 20 if (i>=0) { 21 observers.remove(i); 22 } 23 } 24 @Override 25 public void notifyObservers() { 26 // TODO Auto-generated method stub 27 for (int i = 0; i < observers.size(); i++) { 28 Observer observer = (Observer)observers.get(i); 29 observer.update(temperature, humidity, pressure); 30 } 31 } 32 33 public void measurementChanged(){ 34 notifyObservers(); 35 } 36 37 public void setMeasurements(float tempture,float humidity,float pressure){ //用于测试,可以设定数据 38 this.temperature=tempture; 39 this.humidity=humidity; 40 this.pressure=pressure; 41 measurementChanged(); 42 } 43 }
定义一个观察者类CurrentConditionDisplay类,实现observer接口:
1 package com.nwpulisz.observerpattren; 2 public class CurrentConditionDisplay implements Observer,Display { 3 private float temperature; 4 private float humidity; 5 private float pressure; 6 private Subject weatherData; 7 8 public CurrentConditionDisplay(Subject weatherData){ 9 this.weatherData = weatherData; 10 weatherData.registerObserver(this); 11 } 12 13 public void update(float temperature, float humidity, float pressure) { 14 // TODO Auto-generated method stub 15 this.temperature = temperature; 16 this.humidity = humidity; 17 this.pressure = pressure; 18 display(); 19 } 20 @Override 21 public void display() { 22 // TODO Auto-generated method stub 23 System.out.println("Current conditions,temperature:"+temperature+" humidity:"+ 24 humidity+" pressure:"+pressure); 25 } 26 }
定义测试类WeatherStaticon:
1 package com.nwpulisz.observerpattren; 2 public class WeatherStation { 3 4 public static void main(String[] args) { 5 // TODO Auto-generated method stub 6 WeatherData weatherData = new WeatherData(); 7 Observer currentConditionDisplay = new CurrentConditionDisplay(weatherData); 8 9 weatherData.setMeasurements(22.0f, 23.0f, 25.0f); //output:Current conditions,temperature:22.0 humidity:23.0 pressure:25.0 10 weatherData.setMeasurements(19.0f, 22.3f, 78.9f); //output:Current conditions,temperature:19.0 humidity:22.3 pressure:78.9 11 12 } 13 }
2、使用Java内置的观察者模式
主题继承observable类,观察者继承observer接口,下面的列子用java内置模式实现:
1 package com.nwpulisz.observerjavapattern; 2 import java.util.Observable; 3 public class WeatherData extends Observable { 4 private float temperature; 5 private float humidity; 6 private float pressure; 7 8 public WeatherData(){ 9 10 } 11 12 public void measurementChanged(){ 13 setChanged(); //Observalbe内置方法,标记状态已经改变的事实; 14 //查看源码,其实setChanged就是将Changed=true;另外jdk源码中还有方法clearChanged(),通知观察者之前,将changed=false; 15 notifyObservers(); //Observable接口内置方法; 16 //setChanged之后,才能调用notify方法,这样更有弹性,否则主题变换过于频繁的话,导致主题会不断的通知观察者 17 } 18 19 public void setMeasurements(float temperature,float humidity,float pressure){ 20 this.temperature = temperature; 21 this.humidity = humidity; 22 this.pressure = pressure; 23 measurementChanged(); 24 } 25 public float getTemperature() { //不仅仅是主题推送,观察者可以通过get方法,主动“拉”数据; 26 return temperature; 27 } 28 public float getHumidity() { 29 return humidity; 30 } 31 public float getPressure() { 32 return pressure; 33 } 34 35 }
1 package com.nwpulisz.observerjavapattern; 2 import java.util.Observable; 3 import java.util.Observer; 4 public class CurrentConditionDisplay implements Observer,Display { 5 private Observable observable; 6 private float temperature; 7 private float humidity; 8 private float pressure; 9 10 public CurrentConditionDisplay(Observable observable){ 11 this.observable = observable; 12 observable.addObserver(this); 13 } 14 15 @Override 16 public void update(Observable o, Object arg) { 17 // TODO Auto-generated method stub 18 if (o instanceof WeatherData) { 19 WeatherData weatherData = (WeatherData)o; 20 this.temperature = weatherData.getTemperature(); 21 this.humidity = weatherData.getHumidity(); 22 //this.pressure = weatherData.getPressure(); 23 display(); 24 } 25 } 26 @Override 27 public void display() { 28 // TODO Auto-generated method stub 29 System.out.println("Current conditions,temperature:"+temperature+" humidity:"+ 30 humidity+" pressure:"+pressure); 31 } 32 }
定义测试类WeatherStaticon:
1 package com.nwpulisz.observerjavapattern; 2 import java.util.Observer; 3 public class WeatherStation { 4 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 WeatherData weatherData = new WeatherData(); 8 Observer currentConditionDisplay = new CurrentConditionDisplay(weatherData); 9 10 weatherData.setMeasurements(25.0f, 23.0f, 25.0f); //output:观察者中没有getpress,所以输出结果Current conditions,temperature:25.0 humidity:23.0 pressure:0.0 11 weatherData.setMeasurements(18.0f, 44.3f, 78.9f); //output:观察者中没有getpress,所以输出结果Current conditions,temperature:18.0 humidity:44.3 pressure:0.0 12 13 } 14 }
虽然Java内置了对观察者模式的支持,但是Observable是一个类,而不是一个接口,但是java不支持多继承,可能限制了Observable的复用的能力。
并且看setChanged()方法设计的源码:
1 /** 2 * Marks this <tt>Observable</tt> object as having been changed; the 3 * <tt>hasChanged</tt> method will now return <tt>true</tt>. 4 */ 5 protected synchronized void setChanged() { 6 changed = true; 7 }
用protected修饰,因此,除非继承Observable,否则无法创建Observable实例并组合到自己的对象中来,这样就违背了“多用组合,少用继承”的原则。但是Java内置的观察者模式支持也为开发提供了方便,某些情况下只要符合需求也可以直接使用。
在android开发中,事件响应机制,比如构建内部类,对Button的响应,属于观察者模式;同时Android应用开发使用的典型的MVC设计模式,也是观察者模式。