Kotlin 的 by
keyword 讓我們可以很輕鬆地實作 Delegation Pattern。首先,先讓我們看一下,一般實作 Delegation Pattern 的程式碼。我們看到 Window.area()
委託呼叫給 bound.area()
,就沒有做其他的事情了。當 Shape
的 methods 多的時候,Window
就要實作很多這種的程式碼。
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
當我們使用 Kotlin 的 by
keyword 時,我們就不需要再實作這些委託的程式碼。這使得程式碼相當地精簡,如下。
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
by
keyword 也允許我們使用自己的實作。
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
然而,與繼承不同的是,委託的物件無法呼叫我們自己實作的方法。如下程式碼中,當我們呼叫 Window.printArea()
時,它會委託給 Rectangle.printArea()
,然後在其裡面呼叫的會是 Rectangle.area()
而不是 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