【问题标题】:How kotlin delegation is useful?kotlin 委托有什么用?
【发布时间】:2020-07-17 20:24:01
【问题描述】:

我真的对 kotlin 代表团感到困惑。让我在这里描述一下看起来像 kotlin 委托的常规多态方法。

interface Base {
    fun print()
}
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}
fun main(args: Array<String>) {
    val b : Base = BaseImpl(10)
    b.print() // prints 10
}

我可以将Base接口的任何实现类传递给b变量来调用指定类对象的方法。那么kotlin的委托有什么好处呢?描述为here

interface Base {
    fun print()
}
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}
class Derived(b: Base) : Base by b // why extra line of code? 
                                   // if the above example works fine without it.
fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // prints 10
}

我知道这是两个代码都可以正常工作的简单场景。委托应该有一个好处,这就是 kotlin 引入它的原因。有什么区别?以及 kotlin 委托如何有用?请给我一个工作示例来与多态方法进行比较。

【问题讨论】:

  • 我想知道这是不是更多关于委托本身的优点的问题,而不是关于 Kotlin 如何实现它的问题。
  • 我问它知道 kotlin 委托有什么用?不是代表团如何有用。因为我已经知道代表团的目的。但是 kotlin 的实现让我很困惑。
  • 第一段代码给出的结果与第二段不同。尝试手动实现Derived,你会感觉到不同。
  • 你能写出短代码吗?因为我真的不知道哪个例子可以区分它们。
  • 有很多关于“组合与继承”主题的博客文章,例如。 G。 codingdelight.com/2014/01/16/…thoughtworks.com/de/insights/blog/…

标签: kotlin


【解决方案1】:

还请记住,您不仅限于一名代表。 Kotlin 实现委托的方式类似于 Groovy 等语言中的 traits 实现。您可以通过委托组合不同的功能。 Kotlin 的方式也可以被认为更强大,因为您也可以“插入”不同的实现。

interface Marks {
  fun printMarks()
}

class StdMarks() : Marks {
  override fun printMarks() { println("printed marks") }
}

class CsvMarks() : Marks {
  override fun printMarks() { println("printed csv marks") }
}

interface Totals {
  fun printTotals()
}

class StdTotals : Totals {
  override fun printTotals() { println("calculated and printed totals") }
}

class CheatTotals : Totals {
  override fun printTotals() { println("calculated and printed higher totals") }
}

class Student(val studentId: Int, marks: Marks, totals: Totals) 
  : Marks by marks, Totals by totals

fun main(args:Array<String>) {
  val student = Student(1,StdMarks(), StdTotals())
  student.printMarks()
  student.printTotals()
  val cheater = Student(1,CsvMarks(), CheatTotals())
  cheater.printMarks()
  cheater.printTotals()
}

输出:

printed marks
calculated and printed totals
printed csv marks
calculated and printed higher totals

继承不能做到这一点。

【讨论】:

    【解决方案2】:

    它对于创建装饰器和对象组合非常有用。 Joshua Bloch 在 Effective Java,第 2 版,第 16 条“优先组合优于继承”中展示了一个很好的例子:继承很容易破坏,而装饰器则不然。

    继承:

    class LoggingList<E> : ArrayList<E>() {
    
        override fun add(e: E): Boolean {
            println("added $e")
            return super.add(e)
        }
    
        override fun addAll(e: Collection<E>): Boolean {
            println("added all: $e")
            return super.addAll(e) // oops! Calls [add] internally.
        }
    
    }
    

    代表团:

    class LoggingList<E>(delegate: MutableList<E>) : MutableList<E> by delegate {
    
        override fun add(e: E): Boolean {
            println("added $e")
            return delegate.add(e)
        }
    
        override fun addAll(e: Collection<E>): Boolean {
            println("added all: $e")
            return delegate.addAll(e) // all OK
            // it calls [delegate]'s [add] internally, not ours
        }
    
    }
    

    【讨论】:

    • 我仍然可以在没有 ` : MutableList by delegate` 的情况下在内部调用你能给我一个工作示例吗?所以我可以与多态方法进行比较。
    • 我认为您应该对您的示例进行更多详细说明,以便您可以证明这如您所说的那样“非常有用”。恐怕它不像你建议的那样明显。
    • 首先,这是一个工作示例,只需将其复制并粘贴到 try.kotlinlang.org 并试用即可。第二:Miha 的意思是,addAll 在内部调用 add 在每个新项目上。因此,在继承示例中,您将获得“全部添加”,然后为每个项目“添加 xy”,因为我们覆盖了add()。在委托示例中,您只会得到“全部添加”,因为 addAll 不调用我们的 add,而是调用 MutableList 的 add
    【解决方案3】:

    这很有用,因为 Delegation Pattern 的大部分行为可以与委托的目标 (b) 相同,但您只想覆盖一部分方法以实现不同的行为。

    一个例子是InputStream 实现,它将所有工作委托给另一个InputStream,但覆盖close() 方法以不关闭底层流。这可以实现为:

    class CloseGuardInputStream(private val base: InputStream)
        : InputStream by base {
        override fun close() {}
    }
    

    【讨论】:

    • 你能给出测试的例子吗?所以我可以用接口多态的方式比较那个例子。我知道委托很有用,但 kotlin 的委托如何?
    • 能不能在main方法中调用上面的代码。所以我可以比较一下接口多态的例子吗?
    • 这个例子实际上是行不通的,因为 InputStream 是一个类而不是一个接口。 Kotlin 中的委派仅支持通过接口。
    【解决方案4】:

    以下是示例:-

    interface Mode{
    val color:String
    fun display()
     }
    
    class DarkMode(override val color:String) : Mode{    
    override fun display(){
        println("Dark Mode..."+color)
    }
     }
    class LightMode(override val color:String) : Mode {
    override fun display() { 
        println("Light Mode..."+color) 
    }
    }
    
    class MyCustomMode(val mode: Mode): Mode{
    override val color:String = mode.color
    override fun display() { 
        mode.display()
    }
    }
    

    现在,自定义模式可以复用display()两种模式DarkModeLightMode的功能

    fun main() {
    MyCustomMode(DarkMode("CUSTOM_DARK_GRAY")).display()
    MyCustomMode(LightMode("CUSTOM_LIGHT_GRAY")).display()
    }
    
     /* output:
     Dark Mode...CUSTOM_DARK_GRAY
     Light Mode...CUSTOM_LIGHT_GRAY
    */
    

    Kotlin 原生支持委托模式。 Kotlin 提供 by 关键字来指定我们的自定义模式将委托给的委托对象。 使用 by 关键字我们可以达到与上面代码相​​同的结果。

    class MyCustomMode(val mode: Mode): Mode by mode
    fun main() {
    MyCustomMode(DarkMode("CUSTOM_DARK_GRAY")).display()
    MyCustomMode(LightMode("CUSTOM_LIGHT_GRAY")).display()
    }
    
    /* output:
    Dark Mode...CUSTOM_DARK_GRAY
      Light Mode...CUSTOM_LIGHT_GRAY
     */
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-05
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 2018-05-07
      • 1970-01-01
      • 2017-11-23
      • 2018-03-30
      相关资源
      最近更新 更多