أنماط تصميم Kotlin

أنماط تصميم Kotlin


يقولون أن "أنماط التصميم هي حلول بديلة لأوجه القصور في لغة برمجة معينة". اقتراح مثير للاهتمام ، إلا إذا لم يكن قد قاله المدافعون ليسب ومخطط .


ولكن يبدو أن مطوري لغة 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 { //println(SlowSingleton.value) } 

الإخراج:


 Test started Took 0 ms Took 0 ms Took 0 ms 

ديكور


ثم يأتي الديكور . هذا نمط يسمح لك بإضافة القليل من الوظائف فوق بعض الفئات الأخرى. نعم ، يمكن لـ IntelliJ إنشائه لك. لكن Kotlin ذهب إلى أبعد من ذلك.


ماذا عن كل مرة نضيف فيها مفتاحًا جديدًا في HashMap ، نتلقى رسالة حول هذا؟


في المُنشئ ، يمكنك تحديد مثيل يتم فيه تفويض جميع الطرق باستخدام الكلمة الأساسية.


 /** * Using `by` keyword you can delegate all but overridden methods */ 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" . ستحبها حتى إذا كنت لا تخطط لاستخدام هذه اللغة في المستقبل القريب (على الرغم من عدم وجود سبب لعدم القيام بذلك).

Source: https://habr.com/ru/post/ar421873/


All Articles