什么是观察者模式
在对象之间定义一对多的依赖关系,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
举例说明
比如有一个天气的数据源,和需要获取天气数据的观察者。天气数据不定时更新。而观察者也是随时订阅和取消订阅天气数据源。在订阅时,希望每次天气数据更新时观察者都可以获取信息。
天气数据源作为被观察的主题,需要对外提供订阅、取消订阅、发布天气数据给订阅者功能。此外还有一个更新自己的天气数据的功能,这个更新动作会触发天气数据的发布。所以被观察者抽象类可以如下定义:
public interface Observable {
void addObserver(Observer observer);
void deleteObserver(Observer observer);
void notifyObservers();
void dataChange(String weatherData);
}
其实现类如下:
public class WeatherObservable implements Observable{
private String weatherData;
private List<Observer> observers = new ArrayList<Observer>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void deleteObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(weatherData);
}
}
public void dataChange(String weatherData) {
this.weatherData = weatherData;
notifyObservers();
}
public Object getWeatherData() {
return weatherData;
}
public List<Observer> getObservers() {
return observers;
}
}
观察者需要提供订阅被观察者后,被观察者更新数据通知订阅方的接口功能。观察者抽象类可以如下定义:
public interface Observer {
void update(String weatherData);
}
其中的数据传递对象暂定为String类型。
其实现类为:
public class WeatherObserverA implements Observer {
private String weatherData;
public void update(String weatherData) {
this.weatherData = weatherData;
showWeatherData();
}
public void showWeatherData() {
System.out.println("天气数据更新了:" + weatherData);
}
}
其中为了方便测试类展示,我们给观察者A加入一个展示天气的功能。
测试类如下:
class ObserverTest {
public static void main(String[] args){
WeatherObservable weatherObservable = new WeatherObservable();
WeatherObserverA weatherObserverA = new WeatherObserverA();
weatherObservable.addObserver(weatherObserverA);
weatherObservable.dataChange("当前气温2摄氏度");
weatherObservable.deleteObserver(weatherObserverA);
weatherObservable.dataChange("当前气温1摄氏度");
}
}
测试结果如下
天气数据更新了:当前气温2摄氏度
上述的观察者模式消息触发的方式只有一种,被观察者在消息发生变化时推送给观察者。也可以扩展出观察者拉取消息的模式。
关于观察者模式总结
观察者模式定义了一种存在消息传递依赖关系时对象的组合和运行机制。这种组合关系可以动态的建立和取消。消息发布者和订阅者做到一定程度上的最低耦合关系。
但是观察者模式在实际使用中的缺点也是明显的。比如逐一通知,订阅方收到消息的时间不同,如果有一个订阅方出现问题会导致后续的都出问题,等等。