Kotlinの委任パターン

1. 概要

委譲が継承より優先される多くのユースケースがあります。 Kotlinはこれを言語レベルでサポートしています。
このチュートリアルでは、*委任パターンに対するKotlinのネイティブサポートについて説明し、実際の動作を確認します。

2. 実装

まず、サードパーティのライブラリに次の構造を持つコード例を用意してみましょう。
interface Producer {

    fun produce(): String
}

class ProducerImpl : Producer {

    override fun produce() = "ProducerImpl"
}
次に、*「by」キーワードを使用して*既存の実装を装飾し*、必要な処理を追加します。
class EnhancedProducer(private val delegate: Producer) : Producer by delegate {

    override fun produce() = "${delegate.produce()} and EnhancedProducer"
}
そのため、この例では、_EnhancedProducer_クラスが_Producer_型の_delegate_オブジェクトをカプセル化することを示しました。 また、_Producer_実装の機能を使用することもできます。
最後に、期待どおりに機能することを確認しましょう。
val producer = EnhancedProducer(ProducerImpl())
assertThat(producer.produce()).isEqualTo("ProducerImpl and EnhancedProducer")

3. ユースケース

次に、委任パターンの2つの一般的な使用例を見てみましょう。
まず、委任パターンを使用して*既存の実装を使用して複数のインターフェイスを実装できます*:
class CompositeService : UserService by UserServiceImpl(), MessageService by MessageServiceImpl()
第二に、既存の実装を強化するために、委任を使用できます*。
後者は、前のセクションで行ったことです。 ただし、既存の実装(サードパーティのライブラリコードなど)を変更できない場合は、以下のようなより現実的な例が特に役立ちます。
class SynchronizedProducer(private val delegate: Producer) : Producer by delegate {

    private val lock = ReentrantLock()

    override fun produce(): String {
        lock.withLock {
            return delegate.produce()
        }
    }
}

4. 委任は継承ではありません

ここで、デリゲートはデコレータについて何も知らないことを常に覚えておく必要があります。したがって、_GoFテンプレートメソッド_のようなアプローチを試してはいけません。
例を考えましょう。
interface Service {

    val seed: Int

    fun serve(action: (Int) -> Unit)
}

class ServiceImpl : Service {

    override val seed = 1

    override fun serve(action: (Int) -> Unit) {
        action(seed)
    }
}

class ServiceDecorator : Service by ServiceImpl() {
    override val seed = 2
}
ここでは、デリゲート(_ServiceImpl_)は共通インターフェイスで定義されたプロパティを使用し、デコレーター(_ServiceDecorator_)でそれをオーバーライドします。 ただし、デリゲートの処理には影響しません。
val service = ServiceDecorator()
service.serve {
    assertThat(it).isEqualTo(1)
}
最後に、Kotlinでは、*インターフェイスだけでなくlink:/kotlin-delegated-properties[separate properties]にも委任できることに注意することが重要です*。

5. 結論

このチュートリアルでは、Kotlinインターフェイスの委任について説明しました。使用するタイミング、構成方法、および警告について説明しました。
いつものように、この記事の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/core-kotlin[GitHubで]から入手できます。