原理或定義
定义了对象间的一种一对多依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
结构
观察者Observer:所有潜在的观察者必须实现观察者接口,这个接口只有update方法,当主题改变时,它被调用。
具体观察者ConcreteObserver: 具体观察者可以是任何实现了Observer接口的类。观察者必须注册具体主题,一边接收更新。
可观察者Subject: 主题接口,即可观察者Observable,对象使用此接口注册为观察者,或者把自己从观察者中删除,每个主题可以有多个观察者。
具体可观察者ConcreteSubject: 一个具体主题实现了主题接口,除了注册和撤销之外,具体主题还实现了notifyObservers()方法,这个方法用来在主题状态改变时更新所有观察者。具体主题也可能有设置和获取状态的方法。
類圖
案例和代碼
本模式以天气站项目作为示例Internet气象站项目:
提供温度、气压和湿度的接口
测量数据更新时需时时通知给第三方
需要设计开放型API,便于其他第三方公司也能接入气象站获取数据
WeatherData类:
一个通常的设计方案:
有些问题
1)其他第三方公司接入气象站获取数据的问题
2)无法在运行时动态的添加第三方
用观察者模式设计重新设计的方案:
观察者Observer
public interface Observer {
public void update(float mTemperatrue,float mPressure,float mHumidity);
}
可观察者Subject
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
具体观察者ConcreteObserver
public class CurrentConditions implements Observer {
private float mTemperatrue;
private float mPressure;
private float mHumidity;
@Override
public void update(float mTemperatrue, float mPressure, float mHumidity) {
// TODO Auto-generated method stub
this.mHumidity = mHumidity;
this.mPressure = mPressure;
this.mTemperatrue = mTemperatrue;
display();
}
public void display() {
System.out.println("***Today mTemperatrue:" + mTemperatrue + "***");
System.out.println("***Today mPressure:" + mPressure + "***");
System.out.println("***Today mHumidity:" + mHumidity + "***");
}
}
public class ForcastConditions implements Observer{
private float mTemperatrue;
private float mPressure;
private float mHumidity;
@Override
public void update(float mTemperatrue, float mPressure, float mHumidity) {
// TODO Auto-generated method stub
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
display();
}
public void display()
{
System.out.println("**明天温度:"+(mTemperatrue+Math.random())+"**");
System.out.println("**明天气压:"+(mPressure+10*Math.random())+"**");
System.out.println("**明天湿度:"+(mHumidity+Math.random())+"**");
}
}
具体可观察者ConcreteSubject
public class WeatherDataSt implements Subject{
private float mTemperatrue;
private float mPressure;
private float mHumidity;
private ArrayList<Observer> mObservers;
public WeatherDataSt()
{
mObservers=new ArrayList<Observer>();
}
public float getTemperature()
{
return mTemperatrue;
}
public float getPressure()
{
return mPressure;
}
public float getHumidity()
{
return mHumidity;
}
public void dataChange()
{
notifyObservers();
}
public void setData(float mTemperatrue,float mPressure,float mHumidity)
{
this.mTemperatrue=mTemperatrue;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
dataChange();
}
@Override
public void registerObserver(Observer o) {
// TODO Auto-generated method stub
mObservers.add(o);
}
@Override
public void removeObserver(Observer o) {
// TODO Auto-generated method stub
if(mObservers.contains(o))
{mObservers.remove(o);}
}
@Override
public void notifyObservers() {
// TODO Auto-generated method stub
for(int i=0,len=mObservers.size();i<len;i++)
{
mObservers.get(i).update(getTemperature(), getPressure(), getHumidity());
}
}
}
管理者 / 测试方法
public class InternetWeather {
public static void main(String[] args) {
CurrentConditions mCurrentConditions;
ForcastConditions mForcastConditions;
WeatherDataSt mWeatherDataSt;
mWeatherDataSt=new WeatherDataSt();
mCurrentConditions=new CurrentConditions();
mForcastConditions=new ForcastConditions();
mWeatherDataSt.registerObserver(mCurrentConditions);
mWeatherDataSt.registerObserver(mForcastConditions);
mWeatherDataSt.setData(30, 150, 40);
mWeatherDataSt.removeObserver(mCurrentConditions);
mWeatherDataSt.setData(40, 250, 50);
}
}
使用場景
1、 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
2、 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
優缺點
主要优点有:
1、 Subject和Observer之间是松偶合的,分别可以各自独立改变。
2、 Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点主要有:
1、 松偶合导致代码关系不明显,有时可能难以理解。(废话)
2、 如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。