作为最简单的设计模式,观察者也是应用的相当广泛,看看官方是怎么说的:
观察者模式:定义了对象一对多的依赖,这样一来,当对象改变时,它的所有依赖者都会受到通知并自动更新。
下面考虑一个气象站的例子来实现观察者模式,气象指数一旦有变化,分布在两个地方的显示屏实时更新,考虑以下:
1.一旦气象站数据有更新,观察者(负责显示的设备)必须第一时间知道,而且通知的方式不是观察者向数据源索取,观察者没有那么多精力,数据源有义务一旦数据更新立刻通知观察者
2.数据源weatherdata只有一个,但是观察者有很多个,并且观察者并不是都是一模一样,后续完全可能增加或者删除一个或多个观察者。
3.当我不想观察这个数据,可以动态的取消一个观察者,增加也是一样,原则就是保持流动性
首先定义数据源(主题),为了保持数据的抽象,考虑使用接口:
public interface Info {
void addObserver(InfoObserver observer);
void removeObserver(InfoObserver observer);
void notifyObserver();
}
天气数据要实现此接口:
public class WeatherInfo implements Info{
private int temperature;
private String pollution;
private List<InfoObserver> observers;
private static final String TAG = "WeatherInfo";
public void setTemperature(int temperature) {
if(this.temperature!=temperature)
this.temperature = temperature;
notifyObserver();
}
public void setPollution(String pollution) {
if(!this.pollution.equals(pollution)){
this.pollution = pollution;
notifyObserver();
}
}
public WeatherInfo(int temperature,String pollution){
this.temperature = temperature;
this.pollution = pollution;
observers = new ArrayList<>();
}
@Override
public void addObserver(InfoObserver observer) {
if(!observers.contains(observer)){
observers.add(observer);
Log.d(TAG,"增加观察者 "+observer.getClass().toString());
}
}
@Override
public void removeObserver(InfoObserver observer) {
if(observers.contains(observer)){
observers.remove(observer);
}
}
@Override
public void notifyObserver() {
for(InfoObserver observer: observers){
observer.update(temperature,pollution);
}
}
}
而观察者,显然也应有对应的抽象,想怎么显示,不同的观察者应该会不同:
public interface InfoObserver {
void update(int temperature,String pollution);
}
先建立一个观察者,此观察者只对温度感兴趣:
public class TemperatureObserver implements InfoObserver{
private Info info;
private static final String TAG = "TemperatureObserver";
public TemperatureObserver(Info info){
this.info = info;
info.addObserver(this);
}
@Override
public void update(int temperature,String pollution) {
Log.d(TAG,"当前温度: "+temperature);
}
}
这里有另外一个观察者,对污染程度感兴趣:
public class PollutionObserver implements InfoObserver{
private Info info;
public PollutionObserver(Info info){
this.info = info;
info.addObserver(this);
}
private static final String TAG = "PollutionObserver";
@Override
public void update(int temperature, String pollution) {
Log.d(TAG,"当前污染程度: "+pollution);
}
}
来看测试代码:
WeatherInfo weatherInfo = new WeatherInfo(17,"slight");
InfoObserver weatherObserver = new TemperatureObserver(weatherInfo);
weatherInfo.setTemperature(26);
InfoObserver pollutionObserver = new PollutionObserver(weatherInfo);
weatherInfo.setPollution("serious");
运行结果如下:
11-17 11:33:31.670 26070-26070/com.poxy D/WeatherInfo: 增加观察者 class com.oberveser.TemperatureObserver
11-17 11:33:31.670 26070-26070/com.poxy D/TemperatureObserver: 当前温度: 26
11-17 11:33:31.671 26070-26070/com.poxy D/WeatherInfo: 增加观察者 class com.oberveser.PollutionObserver
11-17 11:33:31.671 26070-26070/com.poxy D/TemperatureObserver: 当前温度: 26
11-17 11:33:31.671 26070-26070/com.poxy D/PollutionObserver: 当前污染程度: serious
其优点有:
1.数据源(主题)真正拥有这些数据并且能控制他们,比起让许多对象控制同一份数据,可以得到更干净的OO设计。两个对象松耦合,他们之间交互,但是不太清楚彼此细节
2.有新的观察者出现,主题代码不需要修改,只要新的观察者去实现observer接口,然后注册即可,改变主题或者观察者,并不影响另外一方,只要他们之间的接口仍然被遵守。