
Mereka mengatakan bahwa "pola desain adalah solusi untuk kekurangan bahasa pemrograman tertentu." Proposisi yang menarik, kalau saja itu tidak dikatakan oleh pembela Lisp dan Skema .
Tetapi tampaknya para pengembang bahasa Kotlin benar-benar memperhatikan pernyataan ini.
Singleton
Tentu saja, pola pertama yang muncul di pikiran adalah Loner. Dan itu dibangun langsung ke dalam bahasa dalam bentuk kata kunci objek :
object JustSingleton { val value : String = "Just a value" }
Sekarang bidang JustSingleton.value
akan dapat diakses dari mana saja dalam paket.
Dan tidak, ini bukan inisialisasi statis, seperti yang terlihat. Mari kita coba menginisialisasi bidang ini dengan beberapa penundaan di dalam:
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") } }
Inisialisasi malas terjadi pada panggilan pertama:
@org.testng.annotations.Test fun testSingleton() { println("Test started") for (i in 1..3) { val total = measureTimeMillis { println(SlowSingleton.value) } println("Took $total ms") } }
Outputnya adalah:
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
Harap dicatat bahwa jika Anda tidak menggunakan objek ini, operasi membutuhkan 0 ms, meskipun objek masih didefinisikan dalam kode Anda.
val total = measureTimeMillis {
Keluaran:
Test started Took 0 ms Took 0 ms Took 0 ms
Dekorator
Kemudian datang Dekorator . Ini adalah pola yang memungkinkan Anda untuk menambahkan sedikit fungsionalitas di atas beberapa kelas lainnya. Ya, IntelliJ dapat membuatnya untuk Anda. Tapi Kotlin melangkah lebih jauh.
Bagaimana setiap kali kita menambahkan kunci baru di HashMap, kita mendapat pesan tentang ini?
Di konstruktor, Anda menentukan contoh yang mendelegasikan semua metode menggunakan kata kunci.
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") } } } }
Perhatikan bahwa kita dapat mengakses elemen peta kita melalui tanda kurung siku dan menggunakan semua metode lain dengan cara yang sama seperti di HashMap biasa.
@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)) }
Metode pabrik
Objek Companion membuatnya mudah untuk menerapkan Metode Pabrik . Ini adalah pola di mana objek mengontrol proses inisialisasi untuk menyembunyikan beberapa rahasia di dalam dirinya.
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) } } }
Sekarang tidak ada yang bisa mengubah usia 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) }
Strategi
Yang terakhir untuk hari ini adalah Strategi . Karena Kotlin memiliki fungsi tingkat tinggi , menerapkan pola ini juga sangat sederhana:
class UncertainAnimal { var makeSound = fun () { println("Meow!") } }
Dan secara dinamis mengubah perilaku:
@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) }
Harap dicatat bahwa ini memang pola Strategi, dan Anda tidak dapat mengubah tanda tangan metode (halo, JS!)
// Won't compile! someAnimal.makeSound = fun (message : String) { println("$message") }
Semua kode tersedia di halaman GitHub saya .
Dan jika Anda tertarik untuk mempelajari lebih lanjut tentang Kotlin dan pola desain bawaannya, ada buku yang bagus, “Kotlin in Action” . Anda akan menyukainya bahkan jika Anda tidak berencana untuk menggunakan bahasa ini dalam waktu dekat (walaupun tidak ada alasan untuk tidak).