Event Bus ونمط Observer في Rust: التنفيذ والأمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

Event Bus ونمط Observer في Rust: التنفيذ والأمثلة

\n\n

Event Bus (ناقل الأحداث) هو نمط معماري يطبق مبدأ publish-subscribe (الناشر-المشترك). في Rust، هذا النمط مفيد بشكل خاص لبناء أنظمة ضعيفة الاقتران، حيث تتواصل المكونات عبر الأحداث دون معرفة بعضها البعض مباشرة. في هذا المقال، سنشرح كيفية إنشاء Event Bus خاص بك باستخدام نمط Observer، وسنستعرض الحلول الجاهزة من نظام Rust البيئي.

\n\n

نمط Observer: الأساسيات

\n\n

يحدد نمط Observer علاقة "واحد-إلى-متعدد" بين الكائنات. عندما يغير كائن واحد (الناشر) حالته، يتم إخطار جميع الكائنات التابعة (المشتركين) تلقائيًا. في Rust، يتم تنفيذ ذلك غالبًا من خلال traits والتوزيع الديناميكي.

\n\n

التنفيذ الأساسي لـ Observer في Rust

\n\n
use std::collections::HashMap;\n\n// Trait للمراقب\ntrait Observer {\n    fn update(&self, event: &str);\n}\n\n// هيكل الناشر\nstruct EventManager {\n    observers: Vec<Box<dyn Observer>>,\n}\n\nimpl EventManager {\n    fn new() -> Self {\n        EventManager {\n            observers: Vec::new(),\n        }\n    }\n\n    fn subscribe(&mut self, observer: Box<dyn Observer>) {\n        self.observers.push(observer);\n    }\n\n    fn notify(&self, event: &str) {\n        for observer in &self.observers {\n            observer.update(event);\n        }\n    }\n}\n\n// مراقب محدد\nstruct Logger;\n\nimpl Observer for Logger {\n    fn update(&self, event: &str) {\n        println!("[Logger] تم استلام الحدث: {}", event);\n    }\n}\n\nfn main() {\n    let mut manager = EventManager::new();\n    manager.subscribe(Box::new(Logger));\n    manager.notify("user.login");\n}\n
\n\n

Event Bus: نسخة موسعة من Observer

\n\n

Event Bus هو ناقل مركزي يقوم بتوجيه الأحداث حسب أنواعها. على عكس Observer البسيط، هنا يتم دعم أنواع مختلفة من الأحداث وتصفية الاشتراكات.

\n\n

تنفيذ Event Bus مع أنواع الأحداث

\n\n
use std::any::Any;\nuse std::collections::HashMap;\nuse std::sync::{Arc, Mutex};\n\n// نوع الحدث\n#[derive(Clone, Debug)]\nenum EventType {\n    UserLogin,\n    UserLogout,\n    DataUpdate,\n}\n\n// هيكل الحدث\n#[derive(Clone, Debug)]\nstruct Event {\n    event_type: EventType,\n    payload: String,\n}\n\n// معالج الحدث\ntype Handler = Arc<dyn Fn(Event) + Send + Sync>;\n\n// ناقل الأحداث\nstruct EventBus {\n    handlers: HashMap<EventType, Vec<Handler>>,\n}\n\nimpl EventBus {\n    fn new() -> Self {\n        EventBus {\n            handlers: HashMap::new(),\n        }\n    }\n\n    fn subscribe<F>(&mut self, event_type: EventType, handler: F)\n    where\n        F: Fn(Event) + 'static + Send + Sync,\n    {\n        self.handlers\n            .entry(event_type)\n            .or_insert_with(Vec::new)\n            .push(Arc::new(handler));\n    }\n\n    fn publish(&self, event: Event) {\n        if let Some(handlers) = self.handlers.get(&event.event_type) {\n            for handler in handlers {\n                handler(event.clone());\n            }\n        }\n    }\n}\n\nfn main() {\n    let mut bus = EventBus::new();\n\n    bus.subscribe(EventType::UserLogin, |event| {\n        println!("المستخدم دخل: {}", event.payload);\n    });\n\n    bus.subscribe(EventType::UserLogin, |event| {\n        // معالج آخر\n        println!("تم تسجيل الدخول: {}", event.payload);\n    });\n\n    bus.publish(Event {\n        event_type: EventType::UserLogin,\n        payload: "user123".to_string(),\n    });\n}\n
\n\n

Event Bus غير متزامن مع Tokio

\n\n

في التطبيقات الواقعية، غالبًا ما تكون هناك حاجة إلى معالجة الأحداث بشكل غير متزامن. لهذا الغرض، تعتبر مكتبة tokio مع قنواتها broadcast خيارًا ممتازًا.

\n\n

استخدام tokio::sync::broadcast

\n\n
use tokio::sync::broadcast;\n\n#[tokio::main]\nasync fn m                    

توصيات