Event Bus ونمط Observer في Rust: التنفيذ والأمثلة
\n\nEvent Bus (ناقل الأحداث) هو نمط معماري يطبق مبدأ publish-subscribe (الناشر-المشترك). في Rust، هذا النمط مفيد بشكل خاص لبناء أنظمة ضعيفة الاقتران، حيث تتواصل المكونات عبر الأحداث دون معرفة بعضها البعض مباشرة. في هذا المقال، سنشرح كيفية إنشاء Event Bus خاص بك باستخدام نمط Observer، وسنستعرض الحلول الجاهزة من نظام Rust البيئي.
\n\nنمط Observer: الأساسيات
\n\nيحدد نمط Observer علاقة "واحد-إلى-متعدد" بين الكائنات. عندما يغير كائن واحد (الناشر) حالته، يتم إخطار جميع الكائنات التابعة (المشتركين) تلقائيًا. في Rust، يتم تنفيذ ذلك غالبًا من خلال traits والتوزيع الديناميكي.
\n\nالتنفيذ الأساسي لـ Observer في Rust
\n\nuse 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\nEvent Bus: نسخة موسعة من Observer
\n\nEvent Bus هو ناقل مركزي يقوم بتوجيه الأحداث حسب أنواعها. على عكس Observer البسيط، هنا يتم دعم أنواع مختلفة من الأحداث وتصفية الاشتراكات.
\n\nتنفيذ Event Bus مع أنواع الأحداث
\n\nuse 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\nEvent Bus غير متزامن مع Tokio
\n\nفي التطبيقات الواقعية، غالبًا ما تكون هناك حاجة إلى معالجة الأحداث بشكل غير متزامن. لهذا الغرض، تعتبر مكتبة tokio مع قنواتها broadcast خيارًا ممتازًا.
استخدام tokio::sync::broadcast
\n\nuse tokio::sync::broadcast;\n\n#[tokio::main]\nasync fn m أيضاً في المكتبة
حاوية حقن التبعية لـ Kotlin: Koin مقابل Kodein مقابل Dagger
العمل مع التواريخ في Kotlin: المكتبات والأدوات (Kotlinx-datetime, Joda-Time, java.time)
العمل مع CSV في Java: مكتبات OpenCSV و Apache Commons CSV
تحديد معدل الطلبات في Go: دليل للحد من سرعة الطلبات
قوائم المهام في C# (.NET): System.Threading.Channels و TPL Dataflow