انتقل إلى المحتوى الرئيسي
الهندسةMar 28, 2026

Deep EVM #22: حقن التبعيات في Rust — ServiceLocator وArc وTrait Objects

OS
Open Soft Team

Engineering Team

حقن التبعيات بدون إطار عمل

Rust ليس لديها حاوية IoC مدمجة مثل Spring أو .NET. بدلاً من ذلك، نستخدم نظام الأنواع والسمات (Traits) لتحقيق حقن التبعيات.

نمط ServiceLocator

use std::sync::Arc;

pub struct ServiceLocator {
    pub db_pool: Arc<PgPool>,
    pub chain_store: Arc<dyn ChainStore + Send + Sync>,
    pub rpc_client: Arc<dyn RpcClient + Send + Sync>,
    pub event_bus: Arc<EventBus>,
}

impl ServiceLocator {
    pub fn new(config: &Config) -> Result<Self> {
        let db_pool = Arc::new(PgPool::connect(&config.database_url).await?);
        let chain_store = Arc::new(PgChainStore::new(db_pool.clone()));
        let rpc_client = Arc::new(HttpRpcClient::new(&config.rpc_url));
        let event_bus = Arc::new(EventBus::new(10000));
        
        Ok(Self { db_pool, chain_store, rpc_client, event_bus })
    }
}

السمات (Traits) للتجريد

#[async_trait]
pub trait ChainStore: Send + Sync {
    async fn save_chain(&self, chain: &Chain) -> Result<()>;
    async fn get_chain(&self, id: Uuid) -> Result<Option<Chain>>;
    async fn list_profitable(&self, min_profit: U256) -> Result<Vec<Chain>>;
}

// التنفيذ الحقيقي
pub struct PgChainStore {
    pool: Arc<PgPool>,
}

#[async_trait]
impl ChainStore for PgChainStore {
    async fn save_chain(&self, chain: &Chain) -> Result<()> {
        sqlx::query("INSERT INTO chains ...")
            .execute(&*self.pool)
            .await?;
        Ok(())
    }
}

// تنفيذ وهمي للاختبار
pub struct MockChainStore {
    chains: Mutex<Vec<Chain>>,
}

#[async_trait]
impl ChainStore for MockChainStore {
    async fn save_chain(&self, chain: &Chain) -> Result<()> {
        self.chains.lock().await.push(chain.clone());
        Ok(())
    }
}

Arc لمشاركة الحالة

Arc<T> (Atomic Reference Counting) يسمح بمشاركة البيانات بين خيوط متعددة بأمان:

let locator = Arc::new(ServiceLocator::new(&config).await?);

// كل مكون يحصل على نسخة من Arc
let searcher = ArbSearcher::new(locator.clone());
let executor = BundleExecutor::new(locator.clone());
let monitor = BlockMonitor::new(locator.clone());

tokio::spawn(searcher.run());
tokio::spawn(executor.run());
tokio::spawn(monitor.run());

الفوائد

  1. قابلية الاختبار — استبدال التنفيذات الحقيقية بوهمية
  2. فصل المسؤوليات — كل مكون يعرف فقط السمة وليس التنفيذ
  3. المرونة — تغيير التنفيذ دون تغيير المستهلكين

الخلاصة

حقن التبعيات في Rust يعتمد على السمات وArc بدلاً من حاويات IoC. النتيجة: كود آمن للأنواع وقابل للاختبار ومفصول بدون حمل وقت التشغيل.

الوسوم