-
Notifications
You must be signed in to change notification settings - Fork 2
Observer pattern
Sven edited this page Jul 13, 2020
·
2 revisions
The first page is my now unused Observer pattern in Rust: It's a borrow (not consume) based observer for trait restricted observers with sized data to sent.
The link and the content below is an example of how to use plus test:
/// observer pattern
/// idea from https://github.com/lpxxn/rust-design-pattern but extended to box for reference
/// and without detaching
use std::{sync::mpsc, boxed::Box, thread};
pub trait IBorrowingObserver<T: Sized> {
fn update(&self, data: &T);
}
pub trait IBorrowingObserverNotifier<'a, T: Sized> {
fn attach(&mut self, observer: Box<&'a dyn IBorrowingObserver<T>>);
fn notify_observers(&self, data: T);
}
struct NotifyingStruct<'a> {
observers: Vec<Box<&'a dyn IBorrowingObserver<ConcreteData>>>,
}
impl<'a> NotifyingStruct<'a> {
pub fn new() -> Self {
NotifyingStruct {
observers: Vec::new(),
}
}
}
struct ConcreteObserver {
id: u32,
}
impl IBorrowingObserver<ConcreteData> for ConcreteObserver {
fn update(&self, data: &ConcreteData) {
println!(
"Observer id:{} received event with data {}!",
self.id, data.content
);
let sender = data.sender.clone();
sender.send(self.id as u64 + data.content).unwrap();
}
}
struct AnotherConcreteObserver {
id: u32,
}
impl IBorrowingObserver<ConcreteData> for AnotherConcreteObserver {
fn update(&self, data: &ConcreteData) {
println!(
"Another observer id:{} received event with data {}!",
self.id, data.content
);
let sender = data.sender.clone();
sender.send(self.id as u64 + data.content * 2).unwrap();
}
}
impl<'a> IBorrowingObserverNotifier<'a, ConcreteData> for NotifyingStruct<'a> {
fn attach(&mut self, observer: Box<&'a dyn IBorrowingObserver<ConcreteData>>) {
self.observers.push(observer);
}
fn notify_observers(&self, data: ConcreteData) {
for item in self.observers.iter() {
item.update(&data);
}
}
}
// must be sized
struct ConcreteData {
content: u64,
sender: mpsc::Sender<u64>,
}
fn main() {
let mut notifier = NotifyingStruct::new();
let observer_a = ConcreteObserver { id: 1 };
let observer_b = ConcreteObserver { id: 2 };
let observer_c = AnotherConcreteObserver { id: 3 };
let boxed_observer_a: Box<&dyn IBorrowingObserver<ConcreteData>> = Box::new(&observer_a);
let boxed_observer_b: Box<&dyn IBorrowingObserver<ConcreteData>> = Box::new(&observer_b);
let boxed_observer_c: Box<&dyn IBorrowingObserver<ConcreteData>> = Box::new(&observer_c);
notifier.attach(boxed_observer_a);
notifier.attach(boxed_observer_b);
notifier.attach(boxed_observer_c);
let (sender, receiver) = mpsc::channel::<u64>();
let data = ConcreteData {
content: 42 as u64,
sender,
};
let test_thread = thread::spawn(move || {
let tester = move |expected: u64| {
let received = receiver.recv().unwrap();
assert_eq!(expected, received, "expected {} got {}", expected, received);
};
tester(1 + 42);
tester(2 + 42);
tester(3 + 42 * 2);
});
notifier.notify_observers(data);
test_thread.join().unwrap();
}