Kotlin:Builderでの創造的デザインパターン

Kotlinの創造的なデザインパターン:ビルダー

1. 前書き

この簡単な記事では、Kotlinでビルダーデザインパターンを実装する方法を説明します。

2. ビルダーパターン

Builderパターンは、よく使用されるものですが、自分で作成することはめったにありません。

多くのパラメータを含む可能性のあるオブジェクトの構築を処理し、構築が完了したらオブジェクトを不変にしたい場合に最適です。

詳細については、Creative Design Patternshereに関するチュートリアルをご覧ください。

3. 実装

Kotlinは、名前付きパラメーターとデフォルトパラメーター、apply()およびdata classなど、従来のBuilderパターン実装の使用を回避する多くの便利な機能を提供します。

そのため、最初に古典的なJavaスタイルの実装を示し、次にKotlinスタイルの短い形式を示します。

3.1. Javaスタイルの実装

外部オブジェクトが直接アクセスすることを望まないため、読み取り専用フィールドを含む1つのクラスFoodOrderの作成を開始しましょう。

class FoodOrder private constructor(builder: FoodOrder.Builder) {

    val bread: String?
    val condiments: String?
    val meat: String?
    val fish: String?

    init {
        this.bread = builder.bread
        this.condiments = builder.condiments
        this.meat = builder.meat
        this.fish = builder.fish
    }

    class Builder {
        // builder code
    }
}

the constructor is private so that only the nested Builder class can access in it.に注意してください

次に、オブジェクトの構築に使用されるネストされたクラスの作成に移ります。

class Builder {

    var bread: String? = null
      private set
    var condiments: String? = null
      private set
    var meat: String? = null
      private set
    var fish: String? = null
      private set

    fun bread(bread: String) = apply { this.bread = bread }
    fun condiments(condiments: String) = apply { this.condiments = condiments }
    fun meat(meat: String) = apply { this.meat = meat }
    fun fish(fish: String) = apply { this.fish = fish }
    fun build() = FoodOrder(this)
}

ご覧のとおり、our Builder has the same fields as the outer class. For each outer field, we have a matching setter method.

セッターメソッドを使用する代わりに、1つ以上の必須フィールドがある場合は、コンストラクターにそれらを設定させましょう。

fluent designアプローチをサポートするために、apply関数を使用していることに注意してください。

最後に、buildメソッドを使用して、FoodOrderコンストラクターを呼び出します。

3.2. コトリンスタイルの実装

Kotlinを最大限に活用するには、Javaで慣れ親しんだいくつかのベストプラクティスを再検討する必要があります。 それらの多くは、より優れた代替品に置き換えることができます。

慣用的なKotlinコードの書き方を見てみましょう:

class FoodOrder private constructor(
  val bread: String?,
  val condiments: String?,
  val meat: String?,
  val fish: String?) {

    data class Builder(
      var bread: String? = null,
      var condiments: String? = null,
      var meat: String? = null,
      var fish: String? = null) {

        fun bread(bread: String) = apply { this.bread = bread }
        fun condiments(condiments: String) = apply { this.condiments = condiments }
        fun meat(meat: String) = apply { this.meat = meat }
        fun fish(fish: String) = apply { this.fish = fish }
        fun build() = FoodOrder(bread, condiments, meat, fish)
    }
}

Kotlin comes with named and default parameters help to minimize the number of overloadsを実行し、関数呼び出しの可読性を向上させます。

また、別のチュートリアルhereで詳しく説明しているKotlinのデータクラス構造を利用することもできます。

最後に、Javaスタイルの実装と同様に、apply()は流暢なセッターの実装に役立ちます。

4. 使用例

簡単に説明すると、次のBuilderパターン実装を使用してFoodOrderオブジェクトを構築する方法を見てみましょう。

val foodOrder = FoodOrder.Builder()
  .bread("white bread")
  .meat("bacon")
  .condiments("olive oil")
  .build()

5. 結論

Builderパターンは、多くのコンストラクターを記述せずに不変オブジェクトを柔軟に作成する方法というオブジェクト指向プログラミングの非常に一般的な問題を解決します。

ビルダーを検討するときは、構築が複雑かどうかに焦点を当てる必要があります。 構築パターンが単純すぎる場合、フレキシブルビルダーオブジェクトを作成する労力は利点をはるかに超える可能性があります。

いつものように、コードはover on Githubで利用できます。