
يقولون أن "أنماط التصميم هي حلول بديلة لأوجه القصور في لغة برمجة معينة". اقتراح مثير للاهتمام ، إلا إذا لم يكن قد قاله المدافعون ليسب ومخطط .
ولكن يبدو أن مطوري لغة Kotlin أخذوا هذا التصريح على محمل الجد.
سينجلتون
بالطبع ، النمط الأول الذي يتبادر إلى الذهن هو لونر. وهي مدمجة مباشرة في اللغة في شكل الكلمة الأساسية للكائن :
object JustSingleton { val value : String = "Just a value" }
الآن يمكن الوصول إلى حقل JustSingleton.value
من أي مكان في الحزمة.
لا ، هذا ليس التهيئة الثابتة ، كما قد يبدو. دعونا نحاول تهيئة هذا الحقل مع بعض التأخير في الداخل:
object SlowSingleton { val value : String init { var uuid = "" val total = measureTimeMillis { println("Computing") for (i in 1..10_000_000) { uuid = UUID.randomUUID().toString() } } value = uuid println("Done computing in ${total}ms") } }
تحدث التهيئة البطيئة في المكالمة الأولى:
@org.testng.annotations.Test fun testSingleton() { println("Test started") for (i in 1..3) { val total = measureTimeMillis { println(SlowSingleton.value) } println("Took $total ms") } }
الإخراج:
Test started Computing Done computing in 5376ms "45f7d567-9b3e-4099-98e6-569ebc26ecdf" Took 5377 ms "45f7d567-9b3e-4099-98e6-569ebc26ecdf" Took 0 ms "45f7d567-9b3e-4099-98e6-569ebc26ecdf" Took 0 ms
يرجى ملاحظة أنه في حالة عدم استخدام هذا الكائن ، تستغرق العملية 0 مللي ثانية ، على الرغم من أن الكائن لا يزال محددًا في التعليمات البرمجية الخاصة بك.
val total = measureTimeMillis {
الإخراج:
Test started Took 0 ms Took 0 ms Took 0 ms
ديكور
ثم يأتي الديكور . هذا نمط يسمح لك بإضافة القليل من الوظائف فوق بعض الفئات الأخرى. نعم ، يمكن لـ IntelliJ إنشائه لك. لكن Kotlin ذهب إلى أبعد من ذلك.
ماذا عن كل مرة نضيف فيها مفتاحًا جديدًا في HashMap ، نتلقى رسالة حول هذا؟
في المُنشئ ، يمكنك تحديد مثيل يتم فيه تفويض جميع الطرق باستخدام الكلمة الأساسية.
class HappyMap<K, V>(val map : MutableMap<K, V> = mutableMapOf()) : MutableMap<K, V> by map{ override fun put(key: K, value: V): V? { return map.put(key, value).apply { if (this == null) { println("Yay! $key") } } } }
لاحظ أنه يمكننا الوصول إلى عناصر خريطتنا من خلال الأقواس المربعة واستخدام جميع الطرق الأخرى بنفس الطريقة المتبعة في HashMap العادية.
@org.testng.annotations.Test fun testDecorator() { val map = HappyMap<String, String>() val result = captureOutput { map["A"] = "B" map["B"] = "C" map["A"] = "C" map.remove("A") map["A"] = "C" } assertEquals(mapOf("A" to "C", "B" to "C"), map.map) assertEquals(listOf("Yay! A", "Yay! B", "Yay! A"), (result)) }
طريقة المصنع
يسهّل كائن Companion تنفيذ طريقة المصنع . هذا هو النمط الذي يتحكم فيه الكائن في عملية التهيئة الخاصة به من أجل إخفاء بعض الأسرار داخله.
class SecretiveGirl private constructor(val age: Int, val name: String = "A girl has no name", val desires: String = "A girl has no desires") { companion object { fun newGirl(vararg desires : String) : SecretiveGirl { return SecretiveGirl(17, desires = desires.joinToString(", ")) } fun newGirl(name : String) : SecretiveGirl { return SecretiveGirl(17, name = name) } } }
الآن لا يمكن لأحد تغيير سن SecretiveGirl:
@org.testng.annotations.Test fun FactoryMethodTest() { // Cannot do this, constructor is private // val arya = SecretiveGirl(); val arya1 = SecretiveGirl.newGirl("Arry") assertEquals(17, arya1.age) assertEquals("Arry", arya1.name) assertEquals("A girl has no desires", arya1.desires) val arya2 = SecretiveGirl.newGirl("Cersei Lannister", "Joffrey", "Ilyn Payne") assertEquals(17, arya2.age) assertEquals("A girl has no name", arya2.name) assertEquals("Cersei Lannister, Joffrey, Ilyn Payne", arya2.desires) }
إستراتيجية
آخر شيء لهذا اليوم هو الإستراتيجية . نظرًا لأن Kotlin يحتوي على وظائف عالية الترتيب ، فإن تنفيذ هذا النمط بسيط جدًا أيضًا:
class UncertainAnimal { var makeSound = fun () { println("Meow!") } }
وتغيير السلوك بشكل ديناميكي:
@org.testng.annotations.Test fun testStrategy() { val someAnimal = UncertainAnimal() val output = captureOutput { someAnimal.makeSound() someAnimal.makeSound = fun () { println("Woof!") } someAnimal.makeSound() } assertEquals(listOf("Meow!", "Woof!"), output) }
يرجى ملاحظة أن هذا هو بالفعل نمط استراتيجي ، ولا يمكنك تغيير توقيع الطريقة (مرحبًا ، JS!)
// Won't compile! someAnimal.makeSound = fun (message : String) { println("$message") }
جميع الشفرات متاحة على صفحة GitHub الخاصة بي .
وإذا كنت مهتمًا بمعرفة المزيد عن Kotlin وأنماط التصميم المضمنة ، فهناك كتاب رائع ، "Kotlin in Action" . ستحبها حتى إذا كنت لا تخطط لاستخدام هذه اللغة في المستقبل القريب (على الرغم من عدم وجود سبب لعدم القيام بذلك).