柏虎资源网

专注编程学习,Python、Java、C++ 教程、案例及资源

Rust观察者模式:用简单代码实现高效事件通知

抛弃复杂概念,用最直观的方式理解观察者模式

重新设计:更易理解的实现

// 定义观察者接口
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 发送邮件: "事件发生: 数据更新"
    日志记录器 [系统监控]: 记录事件 "数据更新"

移除邮件通知后...
【主题】事件发生: 系统重启
    日志记录器 [系统监控]: 记录事件 "系统重启"

观察者模式三步走

  1. 创建主题 - 事件的来源
  2. let mut system_events = Subject::new();
  3. 添加观察者 - 谁关心这些事件
  4. system_events.add_observer(Box::new(EmailNotifier { email: "admin@company.com".to_string() }));
  5. 通知事件 - 当事情发生时
  6. 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");

为什么使用观察者模式?

  1. 解耦:主题不需要知道观察者的具体实现
  2. 扩展性:添加新观察者不影响现有代码
  3. 灵活性:观察者可以自由组合
  4. 事件驱动:响应式编程的基础

常见问题解答

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);

总结:观察者模式的核心

观察者模式就像现实中的"广播系统":

  • 主题是广播电台
  • 观察者是收音机
  • 通知是广播节目

当电台播放节目时,所有调频到这个电台的收音机都能收到。

在代码中应用这个模式:

  1. 确定哪些对象是"电台"(主题)
  2. 确定哪些对象需要"收听"(观察者)
  3. 在事件发生时"广播"通知

记住这个简单口诀:

主题维护观察者列表,事件发生通知所有!

通过这个简化的实现,你应该能够轻松理解并应用观察者模式了!

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言