kotlin委托如何有用?

Asi*_*taq 7 kotlin

我对kotlin代表团感到很困惑.让我来描述这里的常规多态方法,它看起来与kotlin delgation相同.

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
}
Run Code Online (Sandbox Code Playgroud)

我可以将任何实现的Base接口类传递给b变量来调用指定类的对象的方法.那个kotlin代表团的好处是什么?这是在这里描述的.

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
}
Run Code Online (Sandbox Code Playgroud)

我知道这是两个代码都正常工作的简单方案.应该有代表团的好处,这就是kotlin引入它的原因.有什么不同?以及kotlin委托如何有用?请给我一个工作实例来比较多态方法.

Str*_*lok 8

还要记住,您不仅限于一名代表。Kotlin 实现委托的方式类似于traits在 Groovy 等语言中的实现。您可以通过委托组合不同的功能。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()
}
Run Code Online (Sandbox Code Playgroud)

输出:

printed marks
calculated and printed totals
printed csv marks
calculated and printed higher totals
Run Code Online (Sandbox Code Playgroud)

你不能用继承来做到这一点。


Mih*_*x64 6

它对于创建装饰器和对象组合非常有用。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.
    }

}
Run Code Online (Sandbox Code Playgroud)

代表团:

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
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 首先,这是一个工作示例,只需将其复制并粘贴到 try.kotlinlang.org 中并尝试一下。第二:Miha 的意思是,“addAll”在每个新项目上内部调用“add”。因此,在继承示例中,您将获得“添加所有”,然后为每个项目“添加 xy”,因为我们重写了 `add()`。在委托示例中,您只能得到“added all”,因为 addAll 不会调用我们的“add”,而是调用 MutableList 的“add” (2认同)

Kis*_*kae 5

它很有用,因为委托模式的大多数行为可以与delegation(b)的目标相同,但您只想覆盖方法的子集以采取不同的行为.

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

class CloseGuardInputStream(private val base: InputStream)
    : InputStream by base {
    override fun close() {}
}
Run Code Online (Sandbox Code Playgroud)