أنماط التصميم في Rust مع أمثلة كود

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

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

ابدأ الدورة

أنماط التصميم في Rust: دليل عملي مع أمثلة



أنماط التصميم هي حلول مجربة للمشكلات النمطية في التطوير. في Rust، نظرًا لنظام الملكية الفريد ونموذج الذاكرة، يختلف تنفيذ الأنماط الكلاسيكية غالبًا عن اللغات التي تعمل بجمع القمامة. في هذه المقالة، سنشرح ثلاثة أنماط رئيسية: Singleton وBuilder وStrategy، مع تكييفها لتناسب خصائص Rust.



1. نمط Singleton في Rust: حالة عامة بدون unsafe



يضمن Singleton أن يكون للفئة مثيل واحد فقط، ويوفر نقطة وصول عامة إليه. في Rust، يُعد الكريت once_cell أو std::sync::OnceLock المستقر (منذ Rust 1.70) مثاليًا لهذا الغرض.



التنفيذ باستخدام OnceLock

use std::sync::OnceLock;

pub struct Logger { level: String,}

impl Logger { pub fn global() -> &'static Logger { static INSTANCE: OnceLock<Logger> = OnceLock::new(); INSTANCE.get_or_init(|| Logger { level: "info".to_string(), }) }

pub fn log(&self, msg: &str) { println!("[{}] {}", self.level, msg); }}

fn main() { let logger = Logger::global(); logger.log("مرحبًا، Rust!"); // Logger::global() سيعيد نفس المثيل}


المزايا: الأمان (لا يوجد unsafe)، التهيئة البطيئة، أمان الخيوط. العيب هو أن الحالة العامة تعقد عملية الاختبار.



2. نمط Builder: بناء الكائنات المعقدة



يفصل Builder بناء الكائن المعقد عن تمثيله. في Rust، يكون مفيدًا بشكل خاص للهياكل التي تحتوي على العديد من الحقول الاختيارية.



مثال: تكوين عميل HTTP

pub struct HttpClient {    url: String,    timeout: u64,    headers: Vec<(String, String)>,}

pub struct HttpClientBuilder { url: String, timeout: Option<u64>, headers: Vec<(String, String)>,}

impl HttpClientBuilder { pub fn new(url: &str) -> Self { HttpClientBuilder { url: url.to_string(), timeout: None, headers: vec![], } }

pub fn timeout(mut self, secs: u64) -> Self { self.timeout = Some(secs); self }

pub fn header(mut self, key: &str, value: &str) -> Self { self.headers.push((key.to_string(), value.to_string())); self }

pub fn build(self) -> HttpClient { HttpClient { url: self.url, timeout: self.timeout.unwrap_or(30), headers: self.headers, } }}

fn main() { let client = HttpClientBuilder::new("https://api.example.com") .timeout(10) .header("Authorization", "Bearer token123") .build(); println!("Client URL: {}", client.url);}


هام: استخدام self (وليس &self) في دوال builder يتجنب الاستنساخ ويجعل API أكثر مرونة.



3. نمط Strategy: الخوارزميات كاستراتيجيات قابلة للتبديل



يحدد Strategy عائلة من الخوارزميات، ويغلف كل منها، ويجعلها قابلة للتبديل. في Rust، يتم تنفيذ ذلك من خلال traits والإرسال الديناميكي (Box<dyn Trait>).



مثال: نظام الفرز

trait SortStrategy {    fn sort(&self, data: &mut [i32]);}

struct BubbleSort;impl SortStrategy for BubbleSort { fn sort(&self, data: &mut [i32]) { let n = data.len(); for i in 0..n { for j in 0..n - i - 1 { if data[j] > data[j + 1] { data.swap(j, j + 1); } } } }}

struct QuickSort;impl SortStrategy for QuickSort { fn sort(&self, da

المدونات

توصيات الكتب