• 基于Rust语言实现的观察者模式
  • 发布于 2个月前
  • 193 热度
    0 评论
观察者模式介绍
观察者模式是一种软件设计模式,它允许对象(通常称为主题)维护一个称为观察者的依赖项列表,并自动通知它们任何状态更改。许多语言都有这种模式,要么是内置的,要么是在标准库中。

1,首先是Observable,它可以是一个接口,被观察的对象。被观察对象拥有一个观察者列表。
2,Observer,观察者。这也可以是一个接口。
3,ConcreteObservable,保存状态的具体类。如果状态中有任何变化,则调用setState方法,然后调用notify方法反过来通知观察者。
4,ConcreteObserverA/B,处理状态变化的具体观察者。

在Rust中实现观察者模式
新建一个Rust项目:
cargo new rust_observer
我们将从Observer特征开始:
trait Observer {
    fn update(&self, data:&str);
}
这很简单,Observer只有一个方法update,它有一些数据作为参数。

现在实现Subject:
struct Subject<'a> {
    observers: Vec<&'a dyn Observer>,
    state: String,
}

impl<'a> Subject<'a> {
    fn new(state: String) -> Self {
        Self {
            observers: Vec::new(),
            state: state,
        }
    }
    // 堆代码 duidaima.com
    fn attach(&mut self, observer: &'a dyn Observer) {
        self.observers.push(observer);
    }

    fn detach(&mut self, observer: &dyn Observer) {
        self.observers.retain(|o| !std::ptr::eq(*o, observer));
    }
    fn notify(&self) {
        for o in &self.observers {
            o.update(&self.state);
        }
    }

    fn set_state(&mut self, state: String) {
        self.state = state;
        self.notify();
    }
}
1,在Subject结构体中,观察者必须具有与整个结构体相同的生命周期。
2,new方法,即构造函数,非常简单。
3,attach方法,将观察者加入列表中。
4,detach方法,使用指定的闭包进行筛选。闭包返回true的每个元素都保留在vector中,当它返回false时,这些元素被删除。
5,notify方法遍历每个观察者,并在每个观察者上调用update方法。
6,set_state方法改变状态,并调用notify,以便每个观察者都能对状态变化做出反应。

现在建立一个真正的observer:
struct ConcreteObserver {
    name: String,
}

impl Observer for ConcreteObserver {
    fn update(&self, data:&str) {
        println!("{} received data: {}",self.name,data);
    }
}
测试
fn main() {
    let mut subject = Subject::new("initial data".to_string());

    let observer1=ConcreteObserver {
        name: "Observer 1".to_string(),
    };

    let observer2=ConcreteObserver {
        name: "Observer 2".to_string(),
    };
    subject.attach(&observer1);
    subject.attach(&observer2);
    subject.set_state("updated_data".to_string());
    subject.detach(&observer2);
    subject.set_state("Again updated data".to_string());   
    subject.detach(&observer1);
}
1,我们用一些初始数据实例化Subject。
2,然后定义两个观察者,它们都是concreteobserver。每一个都有一个不同的名称。
3,然后我们需要将它们附加到Subject。
4,set_state方法被调用,这会将状态变化发送给两个观察者,并将其打印出来。
5,为了确保detach方法正确运行,我们分离第二个观察者。
6,我们再调用一次set_state方法,我们现在应该只得到一条打印语句。

执行cargo run,结果如下:
Observer 1 received data: updated_data
Observer 2 received data: updated_data
Observer 1 received data: Again updated data
可能的改进
一个可能的改进是使其线程安全,因为现在这个实现不是线程安全的。

用户评论