I was trying to apply observer pattern to Rust. As in other GC languages such as JS or Java, I wanted to send references to the data in Observable
in an event to Observer
. But the compiler kept on giving me headache because of the borrow checker. So because of that I learned of using Rc
but it did not let me mutate the value in Observable
then I used a RefCell
for internal mutability which worked as I wanted. Hoorah I said. But then I realised the Rc
causes a single location to be referred from different places which made the event system on the Observer
obsolete. So after removing the event method from Observer
, I got:
struct Observable<T: Clone> {
value: Rc<RefCell<T>>
}
impl<T: Clone> Observable<T> {
fn new(value: T) -> Observable<T> {
Observable {
value: Rc::new(RefCell::new(value))
}
}
fn set_value(&mut self, value: T) {
*self.value.borrow_mut() = value;
}
fn register(&mut self) -> Observer<T> {
Observer::new(self.value.clone())
}
}
struct Observer<T: Clone> {
value: Rc<RefCell<T>>
}
impl<T: Clone> Observer<T> {
fn new(value: Rc<RefCell<T>>) -> Observer<T> {
Observer {
value
}
}
fn value(&self) -> T {
(*self.value.borrow()).clone()
}
}
Link to Rust Playground
So does the above given code represent an Observer Pattern from a technical point of view? Because otherwise it works for me. But just wanted to know what constitutes an Observer Pattern?
For the Subject, you can test: if the observer is well attach(count the number of observers and check if the one attach is the good one), and after if the observer is well detach. You can also check by adding more than one observer just to be sure your collection of Observers is well implemented.
Observer is a behavioral design pattern. It specifies communication between objects: observable and observers. An observable is an object which notifies observers about the changes in its state. For example, a news agency can notify channels when it receives news.
The observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
Observer is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they're observing.
So does the above given code represent an Observer Pattern from a technical point of view?
NO
But just wanted to know what constitutes an Observer Pattern?
I have updated your code to simulate the Observer Pattern.
#[allow(unused_variables)]
pub trait Events {
fn on_value(&self, value: &str) {}
}
struct Observable {
value: String,
observers: Vec<Box<Events>>,
}
impl Observable {
fn new(value: &str) -> Observable {
Observable {
value: value.to_owned(),
observers: Vec::new(),
}
}
fn set_value(&mut self, value: &str) {
self.value = value.to_owned();
// send event to observers
for observer in &self.observers {
observer.on_value(value);
}
}
fn register<E: Events + 'static>(&mut self, observer: E) {
self.observers.push(Box::new(observer));
}
}
struct Observer;
impl Events for Observer {
fn on_value(&self, value: &str) {
println!("received value: {:?}", value);
}
}
fn main() {
let mut observable = Observable::new("initial value");
observable.register(Observer);
observable.set_value("updated value");
}
The Observable is the subject and it maintains a list of observers. When an new value is set, the Observable notifies the observers.
Link to playground
Blog post about the Observer Pattern in Rust
No, it does not represent the observer pattern.
From wikipedia
The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
What's missing from your implementation is that the observers are not being notified when the observable changes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With