الهندسة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());
الفوائد
- قابلية الاختبار — استبدال التنفيذات الحقيقية بوهمية
- فصل المسؤوليات — كل مكون يعرف فقط السمة وليس التنفيذ
- المرونة — تغيير التنفيذ دون تغيير المستهلكين
الخلاصة
حقن التبعيات في Rust يعتمد على السمات وArc بدلاً من حاويات IoC. النتيجة: كود آمن للأنواع وقابل للاختبار ومفصول بدون حمل وقت التشغيل.
الوسوم