How useful is the delegation of Kotlin?

I am really confused with the delegation of Kotlin. Let me describe a regular polymorphism approach that looks the same as Kotlin degeneration.

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 } 

I can pass any implemented Base interface class to variable b to call the method of the specified class object. Then what is the advantage of the kotlin delegation? What is described 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 } 

I know this is a simple scenario in which both codes work fine. It should be useful to the delegation why Kotlin presented it. What is the difference? and how can delegate Kotlin be helpful? Please give me a working example to compare with the approach to polymorphism.

+5
source share
3 answers

Also remember that you are not limited to just one delegate. The Kotlin delegation implementation method is similar to traits implementation in languages โ€‹โ€‹such as Groovy. You can create various functions through delegates. The Kotlin method can also be considered more powerful, because you can also โ€œplug inโ€ various implementations.

 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() } 

Output:

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

You cannot do this with inheritance.

+4
source

This is useful because of the Delegation Pattern , where most of the behavior may be the same as the purpose of delegation ( b ), but you just want to override a subset of methods to act differently.

An example would be an InputStream implementation that delegates all work to another InputStream , but overrides the close() method so as not to close the underlying stream. This can be implemented as:

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

This is extremely useful for creating decorators and composing objects. Joshua Bloch in Effective Java, 2nd Edition, clause 16, โ€œGood Composition over Inheritance,โ€ shows a good example: inheritance is easy to catch, but decorators are not.

Inheritance:

 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. } } 

Delegation:

 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] [add] internally, not ours } } 
+3
source

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


All Articles