抛弃复杂概念,用最直观的方式理解观察者模式
重新设计:更易理解的实现
// 定义观察者接口
trait Observer {
fn on_event(&self, event: &str);
}
// 定义主题(被观察对象)
struct Subject {
observers: Vec<Box<dyn Observer>>,
}
impl Subject {
// 创建新主题
fn new() -> Self {
Subject {
observers: Vec::new(),
}
}
// 添加观察者
fn add_observer(&mut self, observer: Box<dyn Observer>) {
self.observers.push(observer);
}
// 移除观察者(简化版)
fn remove_observer(&mut self, index: usize) {
if index < self.observers.len() {
self.observers.remove(index);
}
}
// 通知所有观察者
fn notify_all(&self, event: &str) {
println!("【主题】事件发生: {}", event);
for observer in &self.observers {
observer.on_event(event);
}
}
}
// 具体观察者实现
struct EmailNotifier {
email: String,
}
impl Observer for EmailNotifier {
fn on_event(&self, event: &str) {
println!(" 给 {} 发送邮件: \"事件发生: {}\"", self.email, event);
}
}
struct Logger {
name: String,
}
impl Observer for Logger {
fn on_event(&self, event: &str) {
println!(" 日志记录器 [{}]: 记录事件 \"{}\"", self.name, event);
}
}
fn main() {
// 创建主题
let mut system_events = Subject::new();
// 创建观察者
let admin_email = Box::new(EmailNotifier {
email: "admin@company.com".to_string()
});
let app_logger = Box::new(Logger {
name: "系统监控".to_string()
});
// 添加观察者
system_events.add_observer(admin_email);
system_events.add_observer(app_logger);
// 模拟事件发生
system_events.notify_all("用户登录");
system_events.notify_all("数据更新");
// 移除第一个观察者
system_events.remove_observer(0);
println!("\n移除邮件通知后...");
system_events.notify_all("系统重启");
}
运行结果:
【主题】事件发生: 用户登录
给 admin@company.com 发送邮件: "事件发生: 用户登录"
日志记录器 [系统监控]: 记录事件 "用户登录"
【主题】事件发生: 数据更新
给 admin@company.com 发送邮件: "事件发生: 数据更新"
日志记录器 [系统监控]: 记录事件 "数据更新"
移除邮件通知后...
【主题】事件发生: 系统重启
日志记录器 [系统监控]: 记录事件 "系统重启"
观察者模式三步走
- 创建主题 - 事件的来源
- let mut system_events = Subject::new();
- 添加观察者 - 谁关心这些事件
- system_events.add_observer(Box::new(EmailNotifier { email: "admin@company.com".to_string() }));
- 通知事件 - 当事情发生时
- system_events.notify_all("用户登录");
关键概念图解
主题 (Subject)
│
├── 观察者1 (Observer)
│ │
│ └── 具体实现 (如邮件通知)
│
└── 观察者2 (Observer)
│
└── 具体实现 (如日志记录)
1. 主题 (Subject)
- 负责维护观察者列表
- 事件发生时通知所有观察者
- 提供添加/移除观察者的方法
2. 观察者接口 (Observer)
- 定义on_event方法
- 所有具体观察者必须实现这个接口
3. 具体观察者
- 实现on_event方法
- 定义收到通知后的具体行为
实际应用场景
场景1:用户注册系统
let mut user_registration = Subject::new();
// 添加观察者
user_registration.add_observer(Box::new(EmailNotifier {
email: "welcome@company.com".to_string()
}));
user_registration.add_observer(Box::new(DatabaseLogger {
table: "users".to_string()
}));
// 用户注册成功时
user_registration.notify_all("新用户注册: user123");
场景2:温度监控系统
let mut temperature_sensor = Subject::new();
// 添加观察者
temperature_sensor.add_observer(Box::new(AlertSystem {
threshold: 30.0
}));
temperature_sensor.add_observer(Box::new(DisplayUnit {
name: "控制面板".to_string()
}));
// 温度变化时
temperature_sensor.notify_all("当前温度: 28.5°C");
为什么使用观察者模式?
- 解耦:主题不需要知道观察者的具体实现
- 扩展性:添加新观察者不影响现有代码
- 灵活性:观察者可以自由组合
- 事件驱动:响应式编程的基础
常见问题解答
Q: Box<dyn Observer> 是什么?
A: 可以理解为"任何实现了Observer接口的东西"。就像USB接口可以连接各种设备一样。
Q: 为什么用Vec存储观察者?
A: 就像名单一样记录所有关心事件的对象,事件发生时按名单通知。
Q: 如何移除观察者?
A: 示例中使用了索引移除,实际中可以改进为按名称或ID移除。
进阶技巧:带数据的通知
// 定义包含数据的通知
struct TemperatureEvent {
value: f32,
unit: String,
}
trait Observer {
fn on_temperature_change(&self, event: &TemperatureEvent);
}
// 在通知时
let event = TemperatureEvent {
value: 28.5,
unit: "°C".to_string()
};
subject.notify_all(&event);
总结:观察者模式的核心
观察者模式就像现实中的"广播系统":
- 主题是广播电台
- 观察者是收音机
- 通知是广播节目
当电台播放节目时,所有调频到这个电台的收音机都能收到。
在代码中应用这个模式:
- 确定哪些对象是"电台"(主题)
- 确定哪些对象需要"收听"(观察者)
- 在事件发生时"广播"通知
记住这个简单口诀:
主题维护观察者列表,事件发生通知所有!
通过这个简化的实现,你应该能够轻松理解并应用观察者模式了!