Kotlin’s by keyword allows us to easily implement the Delegation Pattern. First of all, let us take a look at a general way to implement the Delegation Pattern. We can see Window.area()
delegates the call to bound.area()
, doesn’t do anything else. When Shape
has many methods, Window
will have to implement many such codes.
interface Shape { fun area(): Int } class Rectangle(private val width: Int, private val height: Int) : Shape { override fun area(): Int = width * height } class Window(private val bound: Shape) : Shape { override fun area(): Int = bound.area() } fun main() { val shape = Window(Rectangle(6, 5)) println("area is ${shape.area()}") } // Output: // area is 30
When we use Kotlin’s by
keywords, we don’t need to implement these delegation code. This makes the code quite compact as below.
interface Shape { fun area(): Int } class Rectangle(private val width: Int, private val height: Int) : Shape { override fun area(): Int = width * height } class Window(private val bound: Shape) : Shape by bound fun main() { val shape = Window(Rectangle(6, 5)) println("area is ${shape.area()}") } // Output: // area is 30
The by
keyword also allows us to use our own implementation.
interface Shape { fun area(): Int fun printArea() } class Rectangle(private val width: Int, private val height: Int) : Shape { override fun area(): Int = width * height override fun printArea() { println("Rectangle area is ${area()}") } } class Window(private val bound: Shape) : Shape by bound { override fun printArea() { println("Window area is ${area()}") } } fun main() { Window(Rectangle(6, 5)).printArea() } // Output: // Window area is 30
However, unlike inheritance, delegated objects cannot call methods of our own implementation. In the following code, when we call Window.printArea()
, it will delegate to Rectangle.printArea()
, and then call Rectangle.area()
instead of Window.area()
.
interface Shape { fun area(): Int fun printArea() } class Rectangle(private val width: Int, private val height: Int) : Shape { override fun area(): Int = width * height override fun printArea() { println("Rectangle area is ${area()}") } } class Window(private val bound: Shape) : Shape by bound { override fun area(): Int = bound.area() * 10 } fun main() { Window(Rectangle(6, 5)).printArea() } // Output: // Rectangle area is 30