1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
//! Contains the ObserverNumberProducer struct that maintains a number, along
//! with a list of observers to changes in that number, as represented by the
//! IObserverNumberChanged trait.
//-----------------------------------------------------------------------------
use std::rc::Rc;
use std::cell::RefCell;
use super::observer_inumberchanged_trait::IObserverNumberChanged;
//-----------------------------------------------------------------------------
/// Represents the Observer Subject in this example, in this case, a struct
/// that contains a single number that is updated with a call to the update()
/// method. Whenever update() is called, the number is incremented and all
/// observers are notified. The observers are passed ("pushed") the changed
/// number through the IObserverNumberChanged trait.
pub struct ObserverNumberProducer {
/// The number being maintained.
number: u32,
/// The list of observers subscribed to this class instance.
observers: Vec<Rc<RefCell<dyn IObserverNumberChanged>>>,
}
impl ObserverNumberProducer {
/// Default constructor
pub fn new() -> ObserverNumberProducer {
ObserverNumberProducer {
number: 0,
observers : vec![],
}
}
/// Call this method to subscribe an observer to this struct for
/// notifications about changing numbers. Does nothing if the given
/// observer is already subscribed.
///
/// # Parameters
/// - observer
///
/// The observer as represented by the IObserverNumberChanged trait.
pub fn add_observer(&mut self, observer: &Rc<RefCell<dyn IObserverNumberChanged>>) {
let found_index = self.find_index_of_observer(observer);
if let None = found_index {
self.observers.push(observer.clone());
}
}
/// Call this method to unsubscribe an observer from this struct so
/// notifications are no longer received. Does nothing if the given
/// observer was not subscribed.
///
/// # Parameters
/// - observer
///
/// The observer as represented by the IObserverNumberChanged trait.
pub fn remove_observer(&mut self, observer: &Rc<RefCell<dyn IObserverNumberChanged>>) {
let found_index = self.find_index_of_observer(observer);
if let Some(index) = found_index {
self.observers.remove(index);
}
}
/// Update the number then notify all observers.
pub fn update(&mut self) {
self.number += 1;
self.notify_observers();
}
/// Helper method to retrieve the index to the specified observer if the
/// observer is in the list.
///
/// # Parameters
/// - observer
///
/// The observer as represented by the IObserverNumberChanged trait.
///
/// # Returns
/// Returns Some(index) if the observer was found; otherwise, returns None.
fn find_index_of_observer(&self, observer: &Rc<RefCell<dyn IObserverNumberChanged>>) -> Option<usize> {
self.observers.iter().position(|x| x.as_ptr() == observer.as_ptr())
}
/// Helper method to notify all observers that the number has changed.
fn notify_observers(&self) {
if !self.observers.is_empty() {
// Copy the list so observers can change the original observers
// during the notification (this isn't strictly needed in this
// example but it is good practice for any notification system
// that handles multiple observers where multiple threads might
// be in play or observers can unsubscribe at any time, even in
// the event notification).
let local_observers: Vec<Rc<RefCell<dyn IObserverNumberChanged>>> = self.observers.clone();
for observer in local_observers.iter() {
observer.borrow_mut().notify(self.number);
}
}
}
}