Event Bus ونمط Observer في Rust: بناء بنية أحداث مرنة
في تطوير البرمجيات الحديثة، غالبًا ما تنشأ الحاجة إلى ترابط ضعيف بين المكونات. يسمح نمط Observer وتطبيقه العملي - Event Bus (ناقل الأحداث) - بتنظيم تفاعل فعال بين الوحدات دون تبعيات مباشرة. يوفر Rust، مع نظام الأنواع الصارم والتركيز على الأمان، إمكانيات ممتازة لتنفيذ هذا النمط. في هذه المقالة، سنشرح كيفية بناء Event Bus خاص بك في Rust، باستخدام الإمكانيات المدمجة للغة والحزم الشائعة.
ما هو Event Bus ونمط Observer؟
نمط Observer يحدد علاقة "واحد إلى متعدد" بين الكائنات: عندما يغير كائن واحد (الناشر) حالته، يتم إخطار جميع الكائنات التابعة (المشتركين) تلقائيًا. Event Bus هو ناقل مركزي يدير الاشتراكات وتوزيع الأحداث، مما يسمح لأي مكون بنشر الأحداث والاشتراك فيها.
المزايا الرئيسية:
- ترابط ضعيف: الناشرون والمشتركون لا يعرفون بعضهم البعض مباشرة
- قابلية التوسع: سهولة إضافة مشتركين جدد دون تغيير الكود الموجود
- قابلية الاختبار: يمكن اختبار المكونات بشكل منفصل عن طريق محاكاة الأحداث
- عدم التزامن: يمكن معالجة الأحداث في الخلفية
تنفيذ أساسي لـ Event Bus في Rust
لنبدأ بتنفيذ متزامن بسيط باستخدام الأدوات القياسية لـ Rust. سيعتمد على HashMap حيث يكون المفتاح هو نوع الحدث والقيمة هي قائمة المعالجات.
use std::collections::HashMap;use std::any::{Any, TypeId};use std::marker::PhantomData;
// نوع الحدث بمعرف فريدpub trait Event: Any + Clone + Send + 'static { fn event_type(&self) -> TypeId { TypeId::of::<Self>() }}
// معالج الحدثpub trait EventHandler<E: Event>: Send + 'static { fn handle(&self, event: &E);}
// ناقل الأحداث نفسهpub struct EventBus { handlers: HashMap<TypeId, Vec<Box<dyn Any>>>,}
impl EventBus { pub fn new() -> Self { EventBus { handlers: HashMap::new(), } }
pub fn subscribe<E: Event, H: EventHandler<E>>(&mut self, handler: H) { let type_id = TypeId::of::<E>(); let boxed_handler = Box::new(handler) as Box<dyn Any>; self.handlers.entry(type_id).or_insert(Vec::new()).push(boxed_handler); }
pub fn publish<E: Event>(&self, event: &E) { let type_id = event.event_type(); if let Some(handlers) = self.handlers.get(&type_id) { for handler in handlers { if let Some(typed_handler) = handler.downcast_ref::<Box<dyn EventHandler<E>>>() { typed_handler.handle(event); } } } }}مثال على الاستخدام
// تعريف الأحداث#[derive(Clone)]struct UserLoggedIn { user_id: u32, username: String,}
impl Event for UserLoggedIn {}
#[derive(Clone)]struct DataUpdated { table: String, record_id: u64,}
impl Event for DataUpdated {}
// تعريف المعالجاتstruct Logger;impl EventHandler<UserLoggedIn> for Logger { fn handle(&self, event: &UserLoggedIn) { println!("[LOG] User {} (ID: {}) logged in", event.username, event.user_id); }}
struct EmailNotifier;impl EventHandler<UserLoggedIn> for EmailNotifier { fn handle(&self, event: &UserLoggedIn) { println!("[EMAIL] Sending welcome email to {}", event.username); }}
fn main() { le