How can I implement the observer pattern in Rust?

后端 未结 5 895
轻奢々
轻奢々 2020-12-28 17:01

I have an observable collection and an observer. I want the observer to be a trait implementation of trait Observer. The observable object should be able to not

5条回答
  •  囚心锁ツ
    2020-12-28 17:30

    The Observer pattern, depending on implementation choices, may pose an ownership challenge.

    In garbage collected languages it is typical to have the Observable referring to the Observer (to notify it) and the Observer referring to the Observable (to unregister itself)... this causes some challenges in terms of ownership (who outlives whom?) and there is this whole "notification on un-registering" thing.

    In Rust (and C++), I advise avoiding cycles.


    Simple solution

    The Observable and Observer have distinct lifetimes, none owning the other or being expected to outlive the other.

    use std::rc::Weak;
    
    struct Event;
    
    trait Observable {
        fn register(&mut self, observer: Weak);
    }
    
    trait Observer {
        fn notify(&self, event: &Event);
    }
    

    The key is to allocate the Observer into a Rc and then hand over Weak (weak references) to the Observable.

    If the Observer needs be modified on the Event, then either it needs internal mutability or it needs to be wrapped into a RefCell (passing Weak> to the Observable).

    When notifying, the Observable will regularly realize that there are dead weak-references (the Observer has disappeared), it can remove those then, lazily.


    There are other solutions, such as using a Broker (quite similar to an event loop), moving from push mode to pull mode (i.e. (1) generate all events, (2) treat all of them), however these depart a bit from the traditional Observer Pattern and have different pluses/minuses so I will not attempt to treat them all here.

提交回复
热议问题