在软件系统中,对象之间经常存在一种依赖关系:当一个对象的状态发生改变时,所有依赖于它的对象都需要得到通知并自动更新。观察者模式正是管理这种依赖关系的完美解决方案。
🎯 模式意图
观察者模式是一种行为设计模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
核心思想:将观察者注册到被观察对象上,被观察对象状态变化时自动通知所有观察者,实现松耦合的发布-订阅机制。
🔍 现实世界比喻
想象一下报纸订阅系统:
-
报社(被观察者)出版新报纸
-
订阅者(观察者)向报社订阅
-
每当有新报纸出版时,报社自动将报纸发送给所有订阅者
-
订阅者可以随时订阅或取消订阅
-
报社不需要知道订阅者的具体信息,只需要维护订阅列表
这种"发布-订阅"的机制正是观察者模式的精髓!
💻 传统处理方式的问题
先来看看我们想要避免的"反模式":
// ❌ 紧耦合的实现:被观察者需要知道所有观察者的细节
class WeatherStation {
private val phoneDisplay = PhoneDisplay()
private val tvDisplay = TVDisplay()
private val webDisplay = WebDisplay()
fun setTemperature(temp: Float) {
// 需要手动调用每个显示设备
phoneDisplay.updateTemperature(temp)
tvDisplay.updateTemperature(temp)
webDisplay.updateTemperature(temp)
}
// 添加新显示器需要修改WeatherStation类
fun addNewDisplay(newDisplay: SomeNewDisplay) {
// 需要修改内部结构,违反开闭原则
}
}
问题分析:
-
紧耦合:被观察者需要知道所有观察者的具体类型
-
违反开闭原则:新增观察者需要修改被观察者代码
-
难以维护:观察者越多,被观察者越复杂
-
无法动态管理:无法在运行时动态添加/删除观察者
🚀 观察者模式的优雅实现
基础观察者模式
// 观察者接口
interface Observer {
fun update(temperature: Float, humidity: Float, pressure: Float)
}
// 被观察者接口
interface Subject {
fun registerObserver(observer: Observer)
fun removeObserver(observer: Observer)
fun notifyObservers()
}
// 具体被观察者:气象站
class WeatherStation : Subject {
private val observers = mutableListOf<Observer>()
private var temperature: Float = 0.0f
private var humidity: Float = 0.0f
private var pressure: Float = 0.0f
override fun registerObserver(observer: Observer) {
observers.add(observer)
}
override fun removeObserver(observer: Observer) {
observers.remove(observer)
}
override fun notifyObservers() {
observers.forEach { it.update(temperature, humidity, pressure) }
}
// 气象数据变化时自动通知所有观察者
fun setMeasurements(temperature: Float, humidity: Float, pressure: Float) {
this.temperature = temperature
this.humidity = humidity
this.pressure = pressure
measurementsChanged()
}
private fun measurementsChanged() {
notifyObservers()
}
}
具体观察者实现
// 手机显示设备
class PhoneDisplay : Observer {
private var currentTemp: Float = 0.0f
override fun update(temperature: Float, humidity: Float, pressure: Float) {
this.currentTemp = temperature
display()
}
private fun display() {
println("📱 手机显示:当前温度 ${currentTemp}°C")
}
}
// 电视显示设备
class TVDisplay : Observer {
private var currentTemp: Float = 0.0f
private var currentHumidity: Float = 0.0f
override fun update(temperature: Float, humidity: Float, pressure: Float) {
this.currentTemp = temperature
this.currentHumidity = humidity
display()
}
private fun display() {
println("📺 电视显示:温度 ${currentTemp}°C,湿度 ${currentHumidity}%")
}
}
// Web显示设备
class WebDisplay : Observer {
private var currentPressure: Float = 0.0f
override fun update(temperature: Float, humidity: Float, pressure: Float) {
this.currentPressure = pressure
display()
}
private fun display() {
println("🌐 网页显示:当前气压 ${currentPressure}hPa")
}
}
客户端使用
fun main() {
// 创建被观察者
val weatherStation = WeatherStation()
// 创建观察者
val phoneDisplay = PhoneDisplay()
val tvDisplay = TVDisplay()
val webDisplay = WebDisplay()
// 注册观察者
weatherStation.registerObserver(phoneDisplay)
weatherStation.registerObserver(tvDisplay)
weatherStation.registerObserver(webDisplay)
println("=== 第一次数据更新 ===")
weatherStation.setMeasurements(25.0f, 65.0f, 1013.25f)
println("\n=== 移除电视显示后更新 ===")
weatherStation.removeObserver(tvDisplay)
weatherStation.setMeasurements(28.0f, 60.0f, 1012.50f)
println("\n=== 添加新的观察者后更新 ===")
val smartWatchDisplay = object : Observer {
override fun update(temperature: Float, humidity: Float, pressure: Float) {
println("⌚ 智能手表:${temperature}°C")
}
}
weatherStation.registerObserver(smartWatchDisplay)
weatherStation.setMeasurements(22.0f, 70.0f, 1014.00f)
}
🌟 高级特性:推模式 vs 拉模式
推模式(Push Model)
// 推模式:被观察者将数据推送给观察者
interface PushObserver {
fun update(data: WeatherData)
}
data class WeatherData(
val temperature: Float,
val humidity: Float,
val pressure: Float,
val windSpeed: Float
)
class PushWeatherStation : Subject {
// ... 注册、移除逻辑类似
fun notifyObservers(data: WeatherData) {
observers.forEach { it.update(data) }
}
}
拉模式(Pull Model)
// 拉模式:观察者从被观察者拉取需要的数据
interface PullSubject {
fun getTemperature(): Float
fun getHumidity(): Float
fun getPressure(): Float
// ... 其他getter方法
}
class PullObserver {
fun update(subject: PullSubject) {
// 观察者只拉取自己需要的数据
val temp = subject.getTemperature()
val humidity = subject.getHumidity()
// ... 处理数据
}
}
🏗️ 事件总线的全局观察者
对于需要全局通信的场景,可以实现事件总线:
// 全局事件总线(单例)
object EventBus {
private val subscribers = mutableMapOf<Class<*>, MutableList<(Any) -> Unit>>()
fun <T : Any> subscribe(eventType: Class<T>, subscriber: (T) -> Unit) {
subscribers.getOrPut(eventType) { mutableListOf() }.add {
subscriber(it as T)
}
}
fun <T : Any> publish(event: T) {
subscribers[event.javaClass]?.forEach { it(event) }
}
}
// 定义事件类
data class UserLoginEvent(val userId: String, val loginTime: Long)
data class OrderCreatedEvent(val orderId: String, val amount: Double)
// 使用事件总线
class LoginService {
fun login(userId: String) {
// ... 登录逻辑
EventBus.publish(UserLoginEvent(userId, System.currentTimeMillis()))
}
}
class AnalyticsService {
init {
EventBus.subscribe(UserLoginEvent::class.java) { event ->
println("📊 记录用户登录统计: ${event.userId}")
}
}
}
📊 模式结构解析
Subject(被观察者) → Observer(观察者接口)
↑ ↑
ConcreteSubject ConcreteObserver
| |
维护观察者列表 实现update方法
notifyObservers() 响应状态变化
-
Subject:被观察者接口,定义注册、移除、通知方法
-
ConcreteSubject:具体被观察者,维护观察者列表,状态改变时通知观察者
-
Observer:观察者接口,定义更新方法
-
ConcreteObserver:具体观察者,实现更新逻辑
🎯 优势总结
|
优势 |
说明 |
|---|---|
|
松耦合 |
被观察者和观察者之间抽象耦合,彼此不知道对方细节 |
|
动态关系 |
可以在运行时动态添加、删除观察者 |
|
开闭原则 |
新增观察者无需修改被观察者代码 |
|
广播通信 |
支持一对多的通信方式,一个变化通知多个对象 |
🔄 与其他模式的关系
-
与中介者模式:都管理对象间通信,但观察者通过松耦合,中介者通过集中控制
-
与责任链模式:观察者广播给所有接收者,责任链顺序传递直到被处理
-
与命令模式:命令对象可以作为通知消息在观察者间传递
💡 实际应用场景
Android LiveData
class MyViewModel : ViewModel() {
private val _userData = MutableLiveData<String>()
val userData: LiveData<String> = _userData
fun updateUserData(newData: String) {
_userData.value = newData
}
}
// Activity中观察数据变化
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel = ViewModelProvider(this)[MyViewModel::class.java]
viewModel.userData.observe(this) { data ->
// 数据变化时自动更新UI
updateUI(data)
}
}
}
React/Vue 响应式系统
// Vue 3 的响应式原理类似观察者模式
const state = reactive({ count: 0 })
// 观察状态变化
watchEffect(() => {
console.log(`计数变为: ${state.count}`)
})
// 触发通知
state.count++ // 自动打印"计数变为: 1"
Java Swing 事件监听
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 按钮点击时被通知
System.out.println("按钮被点击了!");
}
});
Kotlin 属性监听
// 使用委托属性实现属性监听
class ObservableProperty<T>(
initialValue: T,
private val onChange: (oldValue: T, newValue: T) -> Unit
) {
var value: T = initialValue
set(newValue) {
val oldValue = field
field = newValue
onChange(oldValue, newValue)
}
}
class User {
var name: String by ObservableProperty("") { old, new ->
println("名字从 '$old' 改为 '$new'")
}
}
🚀 最佳实践建议
1. 防止内存泄漏
// 在Android中使用Lifecycle避免内存泄漏
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.data.observe(viewLifecycleOwner) { data ->
// 自动在合适的生命周期取消观察
updateUI(data)
}
}
}
2. 异步通知处理
// 支持异步通知的观察者
interface AsyncObserver {
suspend fun updateAsync(data: WeatherData)
}
class AsyncWeatherStation {
private val observers = mutableListOf<AsyncObserver>()
suspend fun notifyObserversAsync(data: WeatherData) {
observers.forEach { observer ->
// 异步通知每个观察者
launch { observer.updateAsync(data) }
}
}
}
3. 通知过滤机制
// 只通知对特定事件感兴趣的观察者
class FilteredEventBus {
fun <T : Any> subscribe(
eventType: Class<T>,
filter: (T) -> Boolean,
subscriber: (T) -> Unit
) {
// 只有满足过滤条件的事件才会被通知
}
}
🌟 响应式编程扩展
观察者模式是现代响应式编程的基石:
// 简单的响应式流实现
class ReactiveStream<T> {
private val subscribers = mutableListOf<(T) -> Unit>()
fun subscribe(onNext: (T) -> Unit) {
subscribers.add(onNext)
}
fun emit(value: T) {
subscribers.forEach { it(value) }
}
}
// 使用响应式流
val clickStream = ReactiveStream<Unit>()
val dataStream = ReactiveStream<String>()
// 组合流
clickStream.subscribe {
dataStream.emit("按钮点击获取的数据")
}
dataStream.subscribe { data ->
println("收到数据: $data")
}
总结
观察者模式通过发布-订阅机制完美解决了对象间的动态依赖关系。它让软件系统更加:
✅ 解耦:观察者和被观察者之间松耦合
✅ 灵活:支持运行时动态管理观察关系
✅ 可扩展:符合开闭原则,易于扩展新观察者
✅ 响应式:为响应式编程奠定基础
从GUI事件处理到响应式框架,从状态管理到消息系统,观察者模式无处不在。掌握这一模式,你将能设计出更加灵活、可维护的软件架构!
观察者模式:实现动态通知
709

被折叠的 条评论
为什么被折叠?



