一:定义:
Observer:Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
二:引入
一个气象观测站的例子:
public
class
WeatherData
...
{
private CurrentConditionsDisplay currentConditionsDisplay;
private ForecastDisplay forecastDisplay;
private StatisticsDisplay statisticsDisplay;
public WeatherData(CurrentConditionsDisplay currentConditionsDisplay,ForecastDisplay forecastDisplay,StatisticsDisplay statisticsDisplay)
...{
this.currentConditionsDisplay=currentConditionsDisplay;
this.forecastDisplay=forecastDisplay;
this.statisticsDisplay=statisticsDisplay;
}
public void mesurementsChanged()
...{
float temp=getTemperature();
float humidity=getHumidity();
float pressure=getPressure();
currentConditionsDisplay.update(temp,humidity,pressure);
forecastDisplay.update(temp,humidity,pressure);
statisticsDisplay.update(temp,humidity,pressure);
}
public float getTemperature()
...{
return 30;
}
public float getHumidity()
...{
return 60;
}
public float getPressure()
...{
return 78;
}
}
public class CurrentConditionsDisplay extends Display ... {
public void update(float temp,float humidity,float pressure)
...{
System.out.println("CurrentConditionsDisplay temp="+temp+",humidity="+humidity+",pressure="+pressure);
}
}
public class Client ... {
public static void main(String[] args) ...{
CurrentConditionsDisplay currentConditionsDisplay=new CurrentConditionsDisplay();
ForecastDisplay forecastDisplay=new ForecastDisplay();
StatisticsDisplay statisticsDisplay=new StatisticsDisplay();
WeatherData weatherData=new WeatherData(currentConditionsDisplay,forecastDisplay,statisticsDisplay);
weatherData.mesurementsChanged();
}
}
private CurrentConditionsDisplay currentConditionsDisplay;
private ForecastDisplay forecastDisplay;
private StatisticsDisplay statisticsDisplay;
public WeatherData(CurrentConditionsDisplay currentConditionsDisplay,ForecastDisplay forecastDisplay,StatisticsDisplay statisticsDisplay)
...{
this.currentConditionsDisplay=currentConditionsDisplay;
this.forecastDisplay=forecastDisplay;
this.statisticsDisplay=statisticsDisplay;
}
public void mesurementsChanged()
...{
float temp=getTemperature();
float humidity=getHumidity();
float pressure=getPressure();
currentConditionsDisplay.update(temp,humidity,pressure);
forecastDisplay.update(temp,humidity,pressure);
statisticsDisplay.update(temp,humidity,pressure);
}
public float getTemperature()
...{
return 30;
}
public float getHumidity()
...{
return 60;
}
public float getPressure()
...{
return 78;
}
}
public class CurrentConditionsDisplay extends Display ... {
public void update(float temp,float humidity,float pressure)
...{
System.out.println("CurrentConditionsDisplay temp="+temp+",humidity="+humidity+",pressure="+pressure);
}
}
public class Client ... {
public static void main(String[] args) ...{
CurrentConditionsDisplay currentConditionsDisplay=new CurrentConditionsDisplay();
ForecastDisplay forecastDisplay=new ForecastDisplay();
StatisticsDisplay statisticsDisplay=new StatisticsDisplay();
WeatherData weatherData=new WeatherData(currentConditionsDisplay,forecastDisplay,statisticsDisplay);
weatherData.mesurementsChanged();
}
}
问题:
耦合太紧,如果增加新的Display,需修改接口和实现。
observer模式:
public
interface
Subject
...
{
public void registerObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyObservers();
}
public class WeatherData implements Subject ... {
private List observerList=new ArrayList();
private float temperature;
private float humidity;
private float pressure;
public WeatherData(float temperature,float humidity,float pressure)
...{
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
}
public void mesurementsChanged()
...{
notifyObservers();
}
public void registerObserver(Observer observer) ...{
observerList.add(observer);
}
public void removeObserver(Observer observer) ...{
observerList.remove(observer);
}
public void notifyObservers() ...{
for(Iterator iter=observerList.iterator();iter.hasNext();)
...{
Observer observer=(Observer)iter.next();
observer.update(temperature,humidity,pressure);
}
}
public float getHumidity() ...{
return humidity;
}
public void setHumidity(float humidity) ...{
this.humidity = humidity;
}
public float getPressure() ...{
return pressure;
}
public void setPressure(float pressure) ...{
this.pressure = pressure;
}
public float getTemperature() ...{
return temperature;
}
public void setTemperature(float temperature) ...{
this.temperature = temperature;
}
}
public interface Observer ... {
public void update(float temp,float humidity,float pressure);
}
public class CurrentConditionsDisplay implements Observer ... {
public void update(float temp,float humidity,float pressure)
...{
System.out.println("CurrentConditionsDisplay temp="+temp+",humidity="+humidity+",pressure="+pressure);
}
}
public class Client ... {
public static void main(String[] args) ...{
WeatherData weatherData=new WeatherData(30,50,60);
Observer currentConditionsDisplay=new CurrentConditionsDisplay();
weatherData.registerObserver(currentConditionsDisplay);
weatherData.mesurementsChanged();
Observer statisticsDisplay=new StatisticsDisplay();
weatherData.registerObserver(statisticsDisplay);
System.out.println("-------------");
weatherData.mesurementsChanged();
weatherData.removeObserver(currentConditionsDisplay);
System.out.println("-------------");
weatherData.mesurementsChanged();
}
}
public void registerObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyObservers();
}
public class WeatherData implements Subject ... {
private List observerList=new ArrayList();
private float temperature;
private float humidity;
private float pressure;
public WeatherData(float temperature,float humidity,float pressure)
...{
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
}
public void mesurementsChanged()
...{
notifyObservers();
}
public void registerObserver(Observer observer) ...{
observerList.add(observer);
}
public void removeObserver(Observer observer) ...{
observerList.remove(observer);
}
public void notifyObservers() ...{
for(Iterator iter=observerList.iterator();iter.hasNext();)
...{
Observer observer=(Observer)iter.next();
observer.update(temperature,humidity,pressure);
}
}
public float getHumidity() ...{
return humidity;
}
public void setHumidity(float humidity) ...{
this.humidity = humidity;
}
public float getPressure() ...{
return pressure;
}
public void setPressure(float pressure) ...{
this.pressure = pressure;
}
public float getTemperature() ...{
return temperature;
}
public void setTemperature(float temperature) ...{
this.temperature = temperature;
}
}
public interface Observer ... {
public void update(float temp,float humidity,float pressure);
}
public class CurrentConditionsDisplay implements Observer ... {
public void update(float temp,float humidity,float pressure)
...{
System.out.println("CurrentConditionsDisplay temp="+temp+",humidity="+humidity+",pressure="+pressure);
}
}
public class Client ... {
public static void main(String[] args) ...{
WeatherData weatherData=new WeatherData(30,50,60);
Observer currentConditionsDisplay=new CurrentConditionsDisplay();
weatherData.registerObserver(currentConditionsDisplay);
weatherData.mesurementsChanged();
Observer statisticsDisplay=new StatisticsDisplay();
weatherData.registerObserver(statisticsDisplay);
System.out.println("-------------");
weatherData.mesurementsChanged();
weatherData.removeObserver(currentConditionsDisplay);
System.out.println("-------------");
weatherData.mesurementsChanged();
}
}
java对Observer模式的支持:
Observable相当于我们上面的Subject,Observer对Observer。对非业务部分方法进行了实现。
package
java.util;
public class Observable ... {
private boolean changed = false;
private Vector obs;
public Observable() ...{
obs = new Vector();
}
public synchronized void addObserver(Observer o) ...{
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) ...{
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) ...{
obs.removeElement(o);
}
public void notifyObservers(Object arg) ...{
Object[] arrLocal;
synchronized (this) ...{
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
}
package java.util;
public interface Observer ... {
void update(Observable o, Object arg);
}
public class Observable ... {
private boolean changed = false;
private Vector obs;
public Observable() ...{
obs = new Vector();
}
public synchronized void addObserver(Observer o) ...{
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) ...{
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) ...{
obs.removeElement(o);
}
public void notifyObservers(Object arg) ...{
Object[] arrLocal;
synchronized (this) ...{
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
}
package java.util;
public interface Observer ... {
void update(Observable o, Object arg);
}
气象站例子对应Java版实现:
public
class
WeatherData
extends
Observable
...
{
private float temperature;
private float humidity;
private float pressure;
public WeatherData(float temperature,float humidity,float pressure)
...{
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
}
public void mesurementsChanged()
...{
setChanged();
notifyObservers();
}
public float getHumidity() ...{
return humidity;
}
public void setHumidity(float humidity) ...{
this.humidity = humidity;
}
public float getPressure() ...{
return pressure;
}
public void setPressure(float pressure) ...{
this.pressure = pressure;
}
public float getTemperature() ...{
return temperature;
}
public void setTemperature(float temperature) ...{
this.temperature = temperature;
}
}
public class CurrentConditionsDisplay implements Observer ... {
public void update(Observable o, Object arg) ...{
if (o instanceof WeatherData)
...{
WeatherData weatherData=(WeatherData)o;
System.out.println("CurrentConditionsDisplay temp="+weatherData.getTemperature()+",humidity="+weatherData.getHumidity()+",pressure="+weatherData.getPressure());
}
}
}
public class Client ... {
public static void main(String[] args) ...{
WeatherData weatherData=new WeatherData(34,44,65);
Observer currentConditionsDisplay=new CurrentConditionsDisplay();
weatherData.addObserver(currentConditionsDisplay);
weatherData.mesurementsChanged();
Observer statisticsDisplay=new StatisticsDisplay();
weatherData.addObserver(statisticsDisplay);
System.out.println("-------------");
System.out.println(weatherData.countObservers());
weatherData.mesurementsChanged();
System.out.println("-------------");
System.out.println(weatherData.countObservers());
weatherData.mesurementsChanged();
}
}
private float temperature;
private float humidity;
private float pressure;
public WeatherData(float temperature,float humidity,float pressure)
...{
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
}
public void mesurementsChanged()
...{
setChanged();
notifyObservers();
}
public float getHumidity() ...{
return humidity;
}
public void setHumidity(float humidity) ...{
this.humidity = humidity;
}
public float getPressure() ...{
return pressure;
}
public void setPressure(float pressure) ...{
this.pressure = pressure;
}
public float getTemperature() ...{
return temperature;
}
public void setTemperature(float temperature) ...{
this.temperature = temperature;
}
}
public class CurrentConditionsDisplay implements Observer ... {
public void update(Observable o, Object arg) ...{
if (o instanceof WeatherData)
...{
WeatherData weatherData=(WeatherData)o;
System.out.println("CurrentConditionsDisplay temp="+weatherData.getTemperature()+",humidity="+weatherData.getHumidity()+",pressure="+weatherData.getPressure());
}
}
}
public class Client ... {
public static void main(String[] args) ...{
WeatherData weatherData=new WeatherData(34,44,65);
Observer currentConditionsDisplay=new CurrentConditionsDisplay();
weatherData.addObserver(currentConditionsDisplay);
weatherData.mesurementsChanged();
Observer statisticsDisplay=new StatisticsDisplay();
weatherData.addObserver(statisticsDisplay);
System.out.println("-------------");
System.out.println(weatherData.countObservers());
weatherData.mesurementsChanged();
System.out.println("-------------");
System.out.println(weatherData.countObservers());
weatherData.mesurementsChanged();
}
}
三:结构
四:实际应用
五:适用情形
Use the Observer pattern in any of the following situations:
- When an abstraction has two aspects, one dependent on the other. Encapsulating these aspects in separate objects lets you vary and reuse them independently.
- When a change to one object requires changing others, and you don't know how many objects need to be changed.
- When an object should be able to notify other objects without making assumptions about who these objects are. In other words, you don't want these objects tightly coupled.
参考文献:
1:阎宏,《Java与模式》,电子工业出版社
2:Eric Freeman & Elisabeth Freeman,《Head First Design Pattern》,O'REILLY
3:GOF,《designpatterns-elements.of.reuseable.object-oriented.software》