From 8cd949d79e17635d03c8619c846b18efc56a5110 Mon Sep 17 00:00:00 2001 From: Alexander Baranov Date: Sat, 7 Mar 2026 16:37:13 +0300 Subject: [PATCH] subscribers - done --- smart-house/README.md | 10 ++++-- .../bin/{room_builder.rs => house_builder.rs} | 0 smart-house/src/bin/subscribers.rs | 22 +++++++++++++ smart-house/src/lib.rs | 2 ++ smart-house/src/room.rs | 32 +++++++++++++++++-- smart-house/src/subscriber.rs | 14 ++++++++ 6 files changed, 75 insertions(+), 5 deletions(-) rename smart-house/src/bin/{room_builder.rs => house_builder.rs} (100%) create mode 100644 smart-house/src/bin/subscribers.rs create mode 100644 smart-house/src/subscriber.rs diff --git a/smart-house/README.md b/smart-house/README.md index ccc3d67..e88640d 100644 --- a/smart-house/README.md +++ b/smart-house/README.md @@ -194,8 +194,8 @@ Добавить возможность добавления callback-ов в объект комнаты, которые срабатывают при добавлении новых устройств в комнату (паттерн Observer). -- [ ] Использовать динамический полиморфизм (трейт-объекты). -- [ ] Можно передавать как объект-subscriber, так и [замыкание](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=06e9dc9bcce297d1e80a22d7e9338ee8). +- [x] Использовать динамический полиморфизм (трейт-объекты). +- [x] Можно передавать как объект-subscriber, так и [замыкание](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=06e9dc9bcce297d1e80a22d7e9338ee8). Добавить example-ы, демонстрирующие новый функционал. @@ -205,3 +205,9 @@ - Приложение-пример успешно выполняется. - Команды cargo clippy и cargo fmt --check не выводят ошибок и предупреждений. - Присутствуют и успешно выполняются модульные тесты. + +### Демонстационные примеры + +- `src/bin/house_builder.rs` - билдер для умного дома +- `src/bin/reporter.rs` - компоновщик для построения отчета +- `src/bin/subscribers.rs` - добавление коллбеков в объект комнаты diff --git a/smart-house/src/bin/room_builder.rs b/smart-house/src/bin/house_builder.rs similarity index 100% rename from smart-house/src/bin/room_builder.rs rename to smart-house/src/bin/house_builder.rs diff --git a/smart-house/src/bin/subscribers.rs b/smart-house/src/bin/subscribers.rs new file mode 100644 index 0000000..680177c --- /dev/null +++ b/smart-house/src/bin/subscribers.rs @@ -0,0 +1,22 @@ +use smart_house::{Device, PowerSocket, Room, Subscriber}; + +fn main() { + let mut room = Room::default(); + + room.subscribe(MySubscriber::default()); + + room.subscribe(|dev: &Device| { + println!("device added: {}", dev.display()); + }); + + room.insert_device("", PowerSocket::stub(12.0, false).into()); +} + +#[derive(Default)] +struct MySubscriber {} + +impl Subscriber for MySubscriber { + fn on_event(&mut self, dev: &Device) { + println!("DEVICE ADDED: {}", dev.display()); + } +} diff --git a/smart-house/src/lib.rs b/smart-house/src/lib.rs index 162173b..e54f81b 100644 --- a/smart-house/src/lib.rs +++ b/smart-house/src/lib.rs @@ -7,6 +7,7 @@ mod room; mod builders; mod print_status; mod reporter; +mod subscriber; mod thermometer; pub use builders::{HouseBuilder, RoomBuilder}; @@ -17,4 +18,5 @@ pub use power_socket::PowerSocket; pub use print_status::PrintStatus; pub use reporter::Reporter; pub use room::Room; +pub use subscriber::Subscriber; pub use thermometer::Thermometer; diff --git a/smart-house/src/room.rs b/smart-house/src/room.rs index 5078307..0437521 100644 --- a/smart-house/src/room.rs +++ b/smart-house/src/room.rs @@ -1,15 +1,19 @@ -use crate::{Device, PrintStatus}; +use crate::{Device, PrintStatus, Subscriber}; use std::collections::HashMap; +use std::fmt::{Debug, Formatter}; use std::io::Write; -#[derive(Debug)] pub struct Room { devices: HashMap, + subscribers: Vec>, } impl Room { pub fn new(devices: HashMap) -> Self { - Self { devices } + Self { + devices, + subscribers: Vec::new(), + } } pub fn get_device(&self, name: &str) -> Option<&Device> { @@ -21,12 +25,19 @@ impl Room { } pub fn insert_device(&mut self, name: &str, device: Device) -> Option { + for subscriber in &mut self.subscribers { + subscriber.on_event(&device); + } self.devices.insert(name.to_string(), device) } pub fn remove_device(&mut self, name: &str) -> Option { self.devices.remove(name) } + + pub fn subscribe(&mut self, subscriber: impl Subscriber + 'static) { + self.subscribers.push(Box::new(subscriber)); + } } impl PrintStatus for Room { @@ -39,6 +50,21 @@ impl PrintStatus for Room { } } +impl Debug for Room { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Room") + .field("devices", &self.devices) + .field("subscribers.len()", &self.subscribers.len()) + .finish() + } +} + +impl Default for Room { + fn default() -> Self { + Room::new(HashMap::new()) + } +} + #[macro_export] macro_rules! room { ($($key:expr => $dev:expr),* $(,)?) => { diff --git a/smart-house/src/subscriber.rs b/smart-house/src/subscriber.rs new file mode 100644 index 0000000..42194ed --- /dev/null +++ b/smart-house/src/subscriber.rs @@ -0,0 +1,14 @@ +use crate::Device; + +pub trait Subscriber { + fn on_event(&mut self, device: &Device); +} + +impl Subscriber for F +where + F: Fn(&Device), +{ + fn on_event(&mut self, value: &Device) { + self(value) + } +}