定义
出版社+订阅者=观察者模式,其中出版社改成为‘主题’,订阅者改称为‘观察者’。观察者模式定义了对象之间的一对多依赖关系,当一个对象改变状态时,他的所有依赖者都会收到通知并且自动更新。这里和订阅报纸是一样的道理,当出版社有了新报纸,那么所有订阅了该报纸的人都会收到新的报纸。
在这里,发生改变的对象(出版社)称为观察目标(主题),被通知的对象(订阅报纸的人)称为观察者,一个观察目标可以对应多个观察者,而这些观察者之间没有相互联系,所以可以根据需要增加和删除观察者,使得系统更易于扩展。
类图
实例
需求
在气象观测站中,有三个布告板,分别显示目前状况,气象统计和天气预报。WeatherData类中具有setter和getter方法,可以取得三个测量值,当有新的数据时,WeatherData类中的measurementsChanged()方法就会被调用,我们要做的就是,一旦WeatherData类有新数据,我们就要更新布告板。
类图设计
代码实现
Subject 主题接口
1 | public interface Subject { |
Observer 观察者接口
1 | public interface Observer { |
DisplayElement 布告板显示接口
1 | public interface DisplayElement { |
WeatherData实现主题接口 WeatherData.java
1 | public class WeatherData implements Subject { |
CurrentConditionsDisplay 布告板
1 | /** |
天气预报布告板
1 | /** |
天气统计布告板
1 | /** |
酷热指数布告板
1 | /** |
测试
1 | public class WeatherStation { |
结果
1 | 我是目前状况布告板,现在温度是:80.0℃湿度是:65.0气压是:30.4 |
执行流程分析
- 实例化一个主题对象(WeatherData)
- 实例化一个现实目前状况的布告板,并传入主题对象。
- 在目前状况的布告板的构造函数中,将当前布告板注册为传入的主题的观察者
- 同理,将天气统计布告板,天气预报布告板,酷热指数布告板都注册为WeatherData的观察者
- 调用主题对象的setMeasurements方法,模拟主题对象的值发生改变。
- 第一次传入不同的温度,湿度和气压。主题对象调用measurementsChanged()方法。
- measurementsChanged()方法中调用notifyObserver()方法。
- notifyObserver()方法中循环调用observer的update()方法,调用的是接口方法,具体执行的是每一个实例类型的update()方法,
- 每一个布告板实例的update()方法,是具体的数据准备,然后调用display()方法,显示布告板信息。
整体分析图
总结
- 观察者模式定义了对象之间的一对多关系,多个观察者监听同一个主题(被观察者),当主题的状态发生改变时,会通知所有的观察者。
- 观察者模式中具体主题是主题的子类,通常包含经常发生改变的数据,当他的状态发生改变时,会通知所有他的观察者对象,主题用一个共同的接口来更新观察者。
- 观察者实现的是同一个接口,也就是主题发生改变时通知的接口,不同的观察者具体的实现方法不一样。
- 观察者与被观察者之间用松耦合的方式结合。