Kotlin设计模式

Kotlin设计模式


他们说:“设计模式是解决特定编程语言缺点的方法。” 辩护者Lisp和Schema只是没有说过一个有趣的主张。


但是,似乎Kotlin语言的开发人员确实将此声明铭记在心。


辛格尔顿


当然,想到的第一个模式是Loner。 它以object关键字的形式直接内置到语言中:


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可以为您创建它。 但是科特林走得更远。


每次我们在HashMap中添加新密钥时,都会收到有关此消息的信息吗?


在构造函数中,您定义一个实例,使用by关键字将所有方法委托给该实例。


 /** * 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对象 ,可以轻松实现Factory方法 。 这是对象控制其初始化过程以在其内部隐藏一些秘密的模式。


 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/zh-CN421873/


All Articles