67
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KotlinAdvent Calendar 2019

Day 21

[Kotlin]`by` で 委譲する仕組みを理解する

Last updated at Posted at 2019-12-18

はじめに

Kotlin には by を使うことで委譲を簡単に実装することができます。
今回はこの仕組みについて理解して内容をまとめたいと思います。

委譲とは?

そもそも委譲についてなのですが Wikipedia では次のように定義されています。
つまり委譲とはあるオブジェクトの操作を一部他のオブジェクトに代替させる手法です。

委譲 (英: delegation) とはオブジェクト指向プログラミングにおいて、
あるオブジェクトの操作を一部他のオブジェクトに代替させる手法のこと。

次のコードは Windowsの操作を Rectangleに委譲している例になります。
Windownamearea()Rectanglename area()を呼び出し、
Windowが実装すべき操作を Rectangleにやらせています。
このような時 Windowの 操作を Rectangleに委譲していると言われます。

interface ClosedShape {
    val name : String
    fun area(): Int
}

class Rectangle(override val name : String, val width: Int, val height: Int) : ClosedShape {
    override fun area() = width * height
}

class Window(private val bounds: ClosedShape) : ClosedShape {
    // Delegation
    override val name = bounds.name
    override fun area() = bounds.area()
}

fun main(args: Array<String>) {
    val rect = Rectangle("rectanble", 10, 10)
    val window = Window(rect)
    println(window.name)
    println(window.area())
}

委譲するのは手間がかかる

委譲するためにあるオブジェクトから他のオブジェクトを呼び出す必要があります。
そのため委譲するメソッドが増えると、他のオブジェクトを呼び出す処理も増えていくことになります。

呼び出し処理が増えていくと、コードの見通しも悪くなっていく問題が発生します。
また呼び出し処理を手作業で記述していくのは面倒で手間がかかります。


interface ClosedShape {
    val name : String
    fun area(): Int
    fun new1()
    fun new2()
    fun new3()
}

class Rectangle(override val name : String, val width: Int, val height: Int) : ClosedShape {
    override fun area() = width * height
    override fun new1() { println("call new1") }
    override fun new2() { println("call new2") }
    override fun new3() { println("call new3") }
}

class Window(private val bounds: ClosedShape) : ClosedShape {
    // Delegation
    override val name = bounds.name
    override fun area() = bounds.area()
    override fun new1() { bounds.new1() }
    override fun new2() { bounds.new2() }
    override fun new3() { bounds.new3() }
}

fun main(args: Array<String>) {
    val rect = Rectangle("rectanble", 10, 10)
    val window = Window(rect)
    println(window.name)
    println(window.area())
    window.new1()
    window.new2()
    window.new3()
}

----- OUTPUT -----
rectanble
100
call new1
call new2
call new3

by を使って簡単に操作を委譲しよう

他のオブジェクトへの委譲を手作業やるとものすごく手間がかかります。
なので Kotlin では by を利用することで操作を他のオブジェクトに委譲できるようになっています。

やり方は簡単で WindowClosedShapeby <インスタンス名称> を追加するだけです。
するとWindowClosedShape の操作を by で指定したインスタンス に全て委譲できます。

interface ClosedShape {
    val name : String
    fun area(): Int
    fun new1()
    fun new2()
    fun new3()
}

class Rectangle(override val name : String, val width: Int, val height: Int) : ClosedShape {
    override fun area() = width * height
    override fun new1() { println("call new1") }
    override fun new2() { println("call new2") }
    override fun new3() { println("call new3") }
}

class Window(private val bounds: ClosedShape) : ClosedShape by bounds

fun main(args: Array<String>) {
    val rect = Rectangle("rectanble", 10, 10)
    val window = Window(rect)
    println(window.name)
    println(window.area())
    window.new1()
    window.new2()
    window.new3()
}

----- OUTPUT -----
rectanble
100
call new1
call new2
call new3

というように by を利用すると インタフェースで実装すべき操作他のオブジェクトへ簡単に委譲できます。
次のように 2つのインタフェースに対して処理を委譲することも可能になっているので、
多くのメソッド・プロパティを持つ複数のインタフェースの処理を委譲していときはすごく便利です。

interface ButtonController {
    fun up()
    fun down()
    fun right()
    fun left()
    fun a()
    fun b()
    fun plus()
    fun minus()
    fun home()
    fun one()
    fun two()
}

interface  GyroController {
    fun xyz(x : Float, y : Float, z : FXMLLoader)
}

class WiiController(private val button : ButtonController, private val gyro: GyroController) 
: ButtonController by button, GyroController by gyro
}

おわりに

本記事の学びは次の3つになると思います。
Kotlin であれば委譲する時には迷わず by を使うのが良さそうです。

  • 委譲とはあるオブジェクトの操作を一部他のオブジェクトに代替させる手法である
  • 委譲ではあるオブジェクトの操作を他のオブジェクトに代替させるため冗長な記述が増えてしまいがち
  • だが Kotlinの by を利用することで冗長な記述をせず、簡単に操作を委譲させることができる。

参考文献

67
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?