观察者模式¶
分类:行为型模式。
类结构¶
classDiagram
direction TB
class Subject {
<<abstract>>
+attach(Observer observer)
+detach(Observer observer)
+notify()
}
class ConcreteSubject {
-String state
+getState() String
+setState(String state)
}
class Observer {
<<interface>>
+update()
}
class ConcreteObserver {
+update()
}
Subject <|-- ConcreteSubject
Observer <|.. ConcreteObserver
Subject o-- "0..*" Observer : 注册并通知
ConcreteObserver --> ConcreteSubject : 拉取状态
角色定义¶
| 角色 | 定义 |
|---|---|
| Subject(主题) | 管理观察者集合,提供注册、移除和通知操作。 |
| ConcreteSubject(具体主题) | 保存被观察的状态,在约定的变化时机通知观察者。 |
| Observer(观察者接口) | 定义接收主题变化通知的更新操作。 |
| ConcreteObserver(具体观察者) | 响应通知并更新自身。图中采用拉取方式,收到 update() 后向具体主题读取状态。 |
Head First 示例:气象站与布告板¶
第 2 章中,气象站采集温度、湿度、气压,当前状况、统计等布告板需要随测量值更新。这里依据作者 2020 年第二版仓库中的 observer/weather 实现。
该版本采用**推送数据**:WeatherData 通知时直接把三个测量值传给 Observer.update()。它与本页通用类图展示的“观察者主动拉取状态”是两种通知方式;不要把两套方法签名混用。图中只选两种布告板,省略预测与酷热指数显示。
| 示例类型 | 模式角色 | 职责 |
|---|---|---|
| Subject | 主题接口 | 定义注册、移除观察者以及发送通知的操作。 |
| WeatherData | 具体主题 | 保存观察者及测量值,在数据改变后推送通知。 |
| Observer | 观察者接口 | 通过带温度、湿度、气压参数的 update() 接收变化。 |
| CurrentConditionsDisplay | 具体观察者 | 保存当前温度与湿度,并显示当前状况。 |
| StatisticsDisplay | 具体观察者 | 累计温度读数,显示平均值、最高值与最低值。 |
| DisplayElement | 显示接口 | 统一布告板的 display() 操作,与订阅接口分离。 |
示例 UML¶
classDiagram
direction TB
class Subject {
<<interface>>
+registerObserver(Observer o)
+removeObserver(Observer o)
+notifyObservers()
}
class WeatherData {
+setMeasurements(temperature, humidity, pressure)
+measurementsChanged()
+notifyObservers()
}
class Observer {
<<interface>>
+update(temp, humidity, pressure)
}
class DisplayElement {
<<interface>>
+display()
}
class CurrentConditionsDisplay {
+update(temperature, humidity, pressure)
+display()
}
class StatisticsDisplay {
+update(temp, humidity, pressure)
+display()
}
Subject <|.. WeatherData
WeatherData o-- "0..*" Observer : 注册并推送
Observer <|.. CurrentConditionsDisplay
Observer <|.. StatisticsDisplay
DisplayElement <|.. CurrentConditionsDisplay
DisplayElement <|.. StatisticsDisplay
CurrentConditionsDisplay --> WeatherData : 订阅主题
StatisticsDisplay --> WeatherData : 订阅主题
协作过程¶
- 创建
WeatherData,再把它传入各布告板构造器;布告板调用registerObserver(this)注册。 - 气象站通过
setMeasurements()更新三个测量值。 measurementsChanged()调用notifyObservers(),逐一执行观察者的update()。- 各布告板更新自己的数据并调用
display();主题只依赖Observer接口。
配套源码(2020 年第二版,固定版本):