Skip to content

Commit 1407e5a

Browse files
committed
Observer pattern
1 parent e2dd64d commit 1407e5a

File tree

6 files changed

+114
-0
lines changed

6 files changed

+114
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ members = [
2121
"behavioral/iterator",
2222
"behavioral/mediator",
2323
"behavioral/memento",
24+
"behavioral/observer",
2425
]

behavioral/observer/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
edition = "2021"
3+
name = "observer"
4+
version = "0.1.0"
5+
6+
[[bin]]
7+
name = "observer"
8+
path = "main.rs"

behavioral/observer/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Observer
2+
3+
In Rust, the convenient way to define a listener is to use a function as a callable object with complex logic.
4+
5+
In this Observer example, Subscribers are either lambda functions or explicit functions subscribed to the event. Explicit function objects could be also unsubscribed (although, there could be limitations for some function types).
6+
7+
```bash
8+
cargo run --bin observer
9+
```
10+
11+
## Execution Result
12+
13+
```
14+
Save log to /path/to/log/file.txt: Load file test1.txt
15+
Save log to /path/to/log/file.txt: Load file test2.txt
16+
Email to [email protected]: Save file test2.txt
17+
```

behavioral/observer/editor.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::observer::{Event, Publisher};
2+
3+
#[derive(Default)]
4+
pub struct Editor {
5+
publisher: Publisher,
6+
file_path: String,
7+
}
8+
9+
impl Editor {
10+
pub fn events(&mut self) -> &mut Publisher {
11+
&mut self.publisher
12+
}
13+
14+
pub fn load(&mut self, path: String) {
15+
self.file_path = path.clone();
16+
self.publisher.notify(Event::Load, path);
17+
}
18+
19+
pub fn save(&self) {
20+
self.publisher.notify(Event::Save, self.file_path.clone());
21+
}
22+
}

behavioral/observer/main.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use editor::Editor;
2+
use observer::Event;
3+
4+
mod editor;
5+
mod observer;
6+
7+
fn main() {
8+
let mut editor = Editor::default();
9+
10+
editor.events().subscribe(Event::Load, |file_path| {
11+
let log = "/path/to/log/file.txt".to_string();
12+
println!("Save log to {}: Load file {}", log, file_path);
13+
});
14+
15+
editor.events().subscribe(Event::Save, save_listener);
16+
17+
editor.load("test1.txt".into());
18+
editor.load("test2.txt".into());
19+
editor.save();
20+
21+
editor.events().unsubscribe(Event::Save, save_listener);
22+
editor.save();
23+
}
24+
25+
fn save_listener(file_path: String) {
26+
let email = "[email protected]".to_string();
27+
println!("Email to {}: Save file {}", email, file_path);
28+
}

behavioral/observer/observer.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::collections::HashMap;
2+
3+
/// An event type.
4+
#[derive(PartialEq, Eq, Hash, Clone)]
5+
pub enum Event {
6+
Load,
7+
Save,
8+
}
9+
10+
/// A subscriber (listener) has type of a callable function.
11+
pub type Subscriber = fn(file_path: String);
12+
13+
/// Publisher sends events to subscribers (listeners).
14+
#[derive(Default)]
15+
pub struct Publisher {
16+
events: HashMap<Event, Vec<Subscriber>>,
17+
}
18+
19+
impl Publisher {
20+
pub fn subscribe(&mut self, event_type: Event, listener: Subscriber) {
21+
self.events.entry(event_type.clone()).or_default();
22+
self.events.get_mut(&event_type).unwrap().push(listener);
23+
}
24+
25+
pub fn unsubscribe(&mut self, event_type: Event, listener: Subscriber) {
26+
self.events
27+
.get_mut(&event_type)
28+
.unwrap()
29+
.retain(|&x| x != listener);
30+
}
31+
32+
pub fn notify(&self, event_type: Event, file_path: String) {
33+
let listeners = self.events.get(&event_type).unwrap();
34+
for listener in listeners {
35+
listener(file_path.clone());
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)