مبادئ SOLID في Rust: النظرية والتطبيق من الألف إلى الياء

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

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

ابدأ الدورة

مقدمة: SOLID و Rust - مزيج مثالي

\n

مبادئ SOLID هي قواعد أساسية للتصميم الموجه للكائنات تساعد في إنشاء كود مرن وقابل للصيانة والتوسع. على الرغم من أن Rust ليست لغة موجهة للكائنات بشكل خالص (فهي تستخدم traits والهياكل بدلاً من الفئات)، إلا أن مبادئ SOLID قابلة للتطبيق عليها بشكل كامل. في هذه المقالة، سنشرح كل مبدأ من المبادئ الخمسة مع أمثلة كود بلغة Rust، موضحين كيف تساعد في بناء أنظمة موثوقة.

\n

خلال المقالة، سترى كيف تجعل Rust مع نظام الملكية (ownership) و traits والأدوية (generics) تطبيق SOLID طبيعيًا وقويًا. سنبدأ بمبدأ المسؤولية الواحدة وننتهي بمبدأ عكس التبعية، مع تقديم أمثلة جاهزة للاستخدام.

\n\n

1. مبدأ المسؤولية الواحدة (SRP)

\n

الجوهر: يجب أن يكون لكل وحدة أو فئة أو دالة سبب واحد فقط للتغيير. في Rust، يعني هذا أن الهيكل يجب أن يكون مسؤولاً عن مهمة واحدة.

\n\n

مثال سيء (انتهاك SRP)

\n
struct Report {\n    title: String,\n    content: String,\n}\n\nimpl Report {\n    fn generate(&self) -> String {\n        format!("# {}\\n\\n{}", self.title, self.content)\n    }\n\n    fn save_to_file(&self, path: &str) -> std::io::Result<()> {\n        std::fs::write(path, self.generate())?;\n        Ok(())\n    }\n\n    fn send_email(&self, recipient: &str) {\n        println!("Sending email to {} with report", recipient);\n    }\n}
\n

هنا، الهيكل Report مسؤول عن التوليد والحفظ والإرسال - ثلاثة أسباب مختلفة للتغيير. هذا ينتهك SRP.

\n\n

مثال جيد (الالتزام بـ SRP)

\n
struct Report {\n    title: String,\n    content: String,\n}\n\nimpl Report {\n    fn generate(&self) -> String {\n        format!("# {}\\n\\n{}", self.title, self.content)\n    }\n}\n\nstruct ReportSaver;\n\nimpl ReportSaver {\n    fn save(&self, report: &Report, path: &str) -> std::io::Result<()> {\n        std::fs::write(path, report.generate())?;\n        Ok(())\n    }\n}\n\nstruct EmailSender;\n\nimpl EmailSender {\n    fn send(&self, recipient: &str, message: &str) {\n        println!("Sending email to {}: {}", recipient, message);\n    }\n}
\n

الآن، كل هيكل مسؤول عن مهمته الخاصة: Report للبيانات والتوليد، ReportSaver للحفظ، EmailSender للإرسال. هذا يبسط الاختبار والصيانة.

\n\n

2. مبدأ الفتح/الإغلاق (OCP)

\n

الجوهر: يجب أن تكون الكيانات البرمجية مفتوحة للتمديد ولكن مغلقة للتعديل. في Rust، يتم تحقيق ذلك من خلال traits والأدوية (generics).

\n\n

مثال: نظام التصفية

\n
trait Filter<T> {\n    fn apply(&self, items: &[T]) -> Vec<T>;\n}\n\nstruct EvenFilter;\n\nimpl Filter<i32> for EvenFilter {\n    fn apply(&self, items: &[i32]) -> Vec<i32> {\n        items.iter().filter(|&x| x % 2 == 0).copied().collect()\n    }\n}\n\nstruct GreaterThanFilter {\n    threshold: i32,\n}\n\nimpl Filter<i32> for GreaterThanFilter {\n    fn apply(&self, items: &[i32]) -> Vec<i32> {\n        items.iter().filter(|&&x| x > self.threshold).copied().collect()\n    }\n}\n\nfn process<T: Clone, F: Filter<T>>(items: &[T], filter: F) -> Vec<T> {\n    filter.apply(items)\n}\n\nfn main() {\n    let numbers = vec![1, 2, 3, 4, 5, 6];\n    let even = process(&numbers, EvenFilter);\n    let greater = process(&numbers, GreaterThanFilter { threshold: 3 });\n    println!("Even: {:?}, Greater: {:?}", even, greater);\n}
\n

يمكننا إضافة مرشحات جديدة دون تعديل الكود الموجود process. هذا هو تطبيق OCP من خلال تعدد الأشكال (polymorphism) باستخدام traits.

\n\n

3. مبدأ استبدال ليسكوف (LSP)

\n

الجوهر:

المدونات

توصيات الكتب