مبادئ SOLID في Kotlin: تطبيق متقدم وممارسة

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

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

ابدأ الدورة

مبادئ SOLID في Kotlin: نظرية وتطبيق على المستوى المتقدم

\n\n

SOLID هي مجموعة أساسية من مبادئ التصميم الشيئي، قدمها روبرت مارتن. في سياق Kotlin، الذي يجمع بين أفضل ميزات البرمجة الشيئية والبرمجة الوظيفية، تكتسب هذه المبادئ إمكانيات جديدة للتنفيذ. في هذه المقالة، سننظر في كل مبدأ على المستوى المتقدم، باستخدام ميزات فريدة للغة: الدوال المضمنة، التفويض، الفئات المختومة ودوال الامتداد.

\n\n

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

\n\n

ينص مبدأ المسؤولية الواحدة على: يجب أن يكون للفصل سبب واحد فقط للتغيير. في Kotlin، للامتثال لـ SRP، غالبًا ما يُستخدم نمط التفويض (Delegation). الكلمة المفتاحية by تسمح بتفويض تنفيذ الواجهة تلقائيًا إلى كائن آخر.

\n\n

المشكلة: الفصل UserService مسؤول عن منطق الأعمال والتسجيل وإرسال البريد الإلكتروني.

\n\n
// ❌ انتهاك SRP\nclass UserService {\n    fun registerUser(email: String, password: String) {\n        // منطق الأعمال\n        println("User registered")\n        // التسجيل\n        log("User registered: $email")\n        // إرسال البريد الإلكتروني\n        sendEmail(email, "Welcome!")\n    }\n\n    private fun log(message: String) { /* ... */ }\n    private fun sendEmail(to: String, body: String) { /* ... */ }\n}\n
\n\n

الحل باستخدام التفويض:

\n\n
// ✅ الامتثال لـ SRP عبر التفويض\ninterface Logger {\n    fun log(message: String)\n}\n\ninterface EmailSender {\n    fun send(to: String, body: String)\n}\n\nclass ConsoleLogger : Logger {\n    override fun log(message: String) = println("LOG: $message")\n}\n\nclass SmtpEmailSender : EmailSender {\n    override fun send(to: String, body: String) = println("Sending email to $to: $body")\n}\n\nclass UserService(\n    private val logger: Logger,\n    private val emailSender: EmailSender\n) : Logger by logger, EmailSender by emailSender { // 👈 تفويض\n\n    fun registerUser(email: String, password: String) {\n        println("User registered")\n        log("User registered: $email")\n        send(email, "Welcome!")\n    }\n}\n\n// الاستخدام\nfun main() {\n    val service = UserService(ConsoleLogger(), SmtpEmailSender())\n    service.registerUser("user@example.com", "pass123")\n}\n
\n\n

استخدام by يتيح تجنب الكود النمطي والفصل الواضح للمسؤوليات. الفصل UserService الآن مسؤول فقط عن التسجيل، بينما تم تفويض التسجيل والإرسال إلى فصول منفصلة.

\n\n

2. مبدأ مفتوح-مغلق (OCP) والفئات المختومة

\n\n

مبدأ مفتوح-مغلق: يجب أن تكون الفصول مفتوحة للتمديد ولكن مغلقة للتعديل. في Kotlin، الفئات المختومة ودوال الامتداد مثالية لهذا الغرض.

\n\n

المشكلة: الدالة processPayment تستخدم when مع التحقق من النوع، وعند إضافة طريقة دفع جديدة، يجب تعديلها.

\n\n
// ❌ انتهاك OCP\nfun processPayment(type: String, amount: Double) {\n    when (type) {\n        "card" -> println("Processing card payment: $amount")\n        "paypal" -> println("Processing PayPal payment: $amount")\n        else -> throw IllegalArgumentException("Unknown payment type")\n    }\n}\n
\n\n

الحل باستخدام الفئات المختومة:

\n\n
// ✅ الامتثال لـ OCP\nsealed class PaymentMethod {\n    data class Card(val number: String, val cvv: String) : PaymentMethod()\n    data class PayPal(val email: String) : PaymentMethod()\n    object Cash : PaymentMethod()\n}\n\n// الدالة مغلقة للتعديل\nfun processPayment(method: PaymentMethod, amount: Double) {\n    // عند ظهور فئات فرعية جديدة، سيطلب المترجم معالجتها\n                

المدونات

توصيات الكتب