1. 概要

デコレータパターンは、構造を変更することなく、同じクラスの他のオブジェクトの動作に影響を与えることなく、既存のオブジェクトに新しい機能を追加できるようにするデザインパターンです。

このチュートリアルでは、Kotlinでこのパターンを実装するためのいくつかの効率的なアプローチについて説明します。

2. デコレータパターン

Decoratorパターンを使用すると、元のオブジェクトに拡張インターフェイスを提供することで、静的または動的に動作を追加できます。 静的アプローチは、継承を使用して実現でき、メインクラスのすべてのメソッドをオーバーライドし、必要な機能を追加します。

継承の代わりに、サブクラス化のオーバーヘッドを減らすために、構成と委任を使用して、動作を動的に追加できます。 この記事では、このパターンを実装するためにこれらの手法に従います。

飾りたいクリスマスツリーオブジェクトの次の例を考えてみましょう。 装飾はオブジェクト自体を変更しません。 クリスマスツリーに加えて、ガーランドやバブルライト、その他のタイプの装飾アイテムを追加しているだけです。

この例を使用して、パターンの実装を見てみましょう。

3. 実装

まず、ChristmasTree汎用インターフェースを作成する必要があります。

interface ChristmasTree {
    fun decorate(): String
}

それでは、このインターフェースの実装を定義しましょう。

class PineChristmasTree : ChristmasTree {

    override fun decorate() = "Christmas tree"
}

次に、ChristmasTreeオブジェクトを装飾するための2つの戦略を見ていきます。

3.1. 作曲で飾る

コンポジションを使用してデコレータパターンを実装する場合、ターゲットオブジェクトのコンポーザまたはデコレータとして機能する抽象クラスが必要です

abstract class TreeDecorator
    (private val tree: ChristmasTree) : ChristmasTree {

    override fun decorate(): String {
        return tree.decorate()
    }
}

次に、装飾要素を作成します。 このデコレータは、抽象 TreeDecorator クラスを拡張し、要件に応じて decode()メソッドを変更します。

class BubbleLights(tree: ChristmasTree) : TreeDecorator(tree) {

    override fun decorate(): String {
        return super.decorate() + decorateWithBubbleLights()
    }

    private fun decorateWithBubbleLights(): String {
        return " with Bubble Lights"
    }
}

これで、装飾されたChristmasTreeオブジェクトを作成できます。

fun christmasTreeWithBubbleLights() {

    val christmasTree = BubbleLights(PineChristmasTree())
    val decoratedChristmasTree = christmasTree.decorate()
    println(decoratedChristmasTree)
}

3.2. 代表団による装飾

委任パターンは実装継承の優れた代替手段であることが証明されており、Kotlinはそれをネイティブにサポートしており、ボイラープレートコードは不要です。 この機能により、 by キーワードを使用して、クラス委任を使用してデコレータを簡単に作成できます。

次に、 decode()メソッドを指定されたオブジェクトに委任することにより、ChristmasTreeインターフェイスを実装できるクラスを定義します。

class Garlands(private val tree: ChristmasTree) : ChristmasTree by tree {

    override fun decorate(): String {
        return tree.decorate() + decorateWithGarlands()
    }

    private fun decorateWithGarlands(): String {
        return " with Garlands"
    }
}

これで、装飾されたChristmasTreeオブジェクトを作成できます。

fun christmasTreeWithGarlands() {

    val christmasTree = Garlands(PineChristmasTree())
    val decoratedChristmasTree = christmasTree.decorate()
    println(decoratedChristmasTree)
}

4. 結論

この記事では、Kotlinでデコレータパターンを実装するためのいくつかの効率的なアプローチについて説明しました。 このパターンは、動作を追加したい場合、または特定のオブジェクトの機能を強化または削除したい場合に役立ちます。 また、Kotlinは、クラスの委任でこのパターンを実装するためのネイティブサポート機能を提供していることもわかりました。

いつものように、この記事の完全なコードは、GitHubから入手できます。