مقدمة: لماذا إعادة هيكلة الكود القديم بلغة Kotlin ليست مجرد إعادة كتابة
العمل مع الكود القديم (legacy code) بلغة Kotlin ليس مجرد استبدال ميكانيكي لتركيبات Java بتركيبات اللغة. إنها عملية استراتيجية تهدف إلى تحسين قابلية القراءة والأمان والأداء للكود دون تغيير سلوكه الخارجي. في هذه المقالة، سنستعرض تقنيات متقدمة لإعادة الهيكلة ستساعدك على تحويل "حديقة الحيوانات" الفوضوية من الفئات إلى نظام منظم وقابل للصيانة. لن نتطرق إلى الأساسيات مثل var مقابل val — بل سنركز على ما يغير البنية حقًا.
1. الترحيل من Java: استبدال getters و setters وفئات الأدوات المساعدة
المشكلة الأكثر شيوعًا في الكود القديم هي وفرة فئات Java مع getters و setters صريحة، بالإضافة إلى فئات الأدوات المساعدة الثابتة. تقدم Kotlin حلولًا أنيقة.
1.1. الوصول القائم على الخصائص بدلاً من Java Beans
بدلاً من كتابة user.getName() و user.setName("Alice")، استخدم خصائص Kotlin. هذه ليست مجرد سكر نحوي: تحصل على واجهة وصول موحدة يمكن تجاوزها.
// Java legacypublic class User { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}
// Kotlin refactoreddata class User(val name: String) // أو مع var إذا كانت القابلية للتغيير مطلوبةإذا كان منطق getter/setter أكثر تعقيدًا (مثل التحقق من الصحة)، استخدم أدوات الوصول المخصصة:
class User { var name: String = "" set(value) { field = value.trim() // قص المسافات تلقائيًا }}1.2. Extension functions بدلاً من الأدوات المساعدة الثابتة
غالبًا ما يحتوي الكود القديم على فئات مثل StringUtils أو FileUtils. في Kotlin، يتم استبدالها بـ extension functions. وهذا يجعل الكود أكثر قابلية للقراءة ويقترب من نمط "طريقة الكائن".
// Java: StringUtils.isNullOrEmpty(str)// Kotlin: str.isNullOrEmpty() (موجودة بالفعل في stdlib)
// مثال على extension خاصة بكfun String.isValidEmail(): Boolean { return this.contains("@") && this.contains(".")}
// الاستخدامval email = "user@example.com"if (email.isValidEmail()) { ... }2. العمل مع null safety: استبدال Optional والتحقق من null
غالبًا ما يعاني كود Java القديم من NullPointerException. تحل Kotlin هذه المشكلة على مستوى الأنواع، ولكن عند إعادة الهيكلة، يجب استبدال Optional وسلاسل التحقق من null بحذر.
2.1. استبدال Optional بأنواع قابلة للقيمة null
بدلاً من Optional<String>، استخدم String?. وهذا يقلل من التكلفة الإضافية لإنشاء الكائن ويجعل الكود أكثر إيجازًا.
// Javapublic Optional<String> findName() { ... }
// Kotlinfun findName(): String? { ... }لسلاسل الاستدعاءات، استخدم العامل ?. وعامل الإلفيس ?::
// بدلاً من if (user != null && user.address != null) ...val city = user?.address?.city ?: "Unknown"2.2. استخدام require() و check() للثوابت
بدلاً من التحقق اليدوي في بداية الدوال، استخدم الدوال المضمنة:
fun processUser(user: User?) { requireNotNull(user) { "يجب ألا يكون المستخدم فارغًا" } // أو require(user != null) { ... } // متابعة العمل مع user (smart cast)}3. إعادة هيكلة المنطق الشرطي: sealed classes و when
كتل ضخمة من if-else أو switch هي علامة على الكود القديم. في Kotlin، يمكن استبدالها بـ sealed class و when الشامل.
3.1. استبدال enum مع الحقول بـ sealed class
إذا كان لديك enum يخزن أنواعًا مختلفة من البيانات لكل قيمة