ビルダーパターンはいつ使用しますか? [closed] 質問する

ビルダーパターンはいつ使用しますか? [closed] 質問する

Builder パターンを使用する一般的な実例にはどのようなものがありますか? Builderパターンによって何が得られますか? Factory パターンを使用しないのはなぜですか?

ベストアンサー1

以下は、Java でパターンとサンプル コードを使用する理由の一部ですが、これは Gang of Four のDesign Patternsで取り上げられている Builder パターンの実装です。Java でこれを使用する理由は、他のプログラミング言語にも当てはまります。

ジョシュア・ブロックは次のように述べている。効果的な Java、第 2 版:

ビルダー パターンは、コンストラクターまたは静的ファクトリに多数のパラメーターが含まれるクラスを設計する場合に適しています。

私たちは皆、コンストラクターのリストを持ち、追加するたびに新しいオプション パラメーターが追加されるクラスに遭遇したことがあります。

Pizza(int size) { ... }        
Pizza(int size, boolean cheese) { ... }    
Pizza(int size, boolean cheese, boolean pepperoni) { ... }    
Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) { ... }

これはテレスコープ コンストラクター パターンと呼ばれます。このパターンの問題点は、コンストラクターのパラメーターが 4 または 5 になると、パラメーターの必要な順序や、特定の状況で必要な特定のコンストラクターを覚えておくのが難しくなることです。

テレスコープ コンストラクター パターンの代替案の1 つは、必須パラメーターを使用してコンストラクターを呼び出し、その後にオプションのセッターを呼び出すJavaBean パターンです。

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

ここでの問題は、オブジェクトが複数の呼び出しにわたって作成されるため、作成の途中で一貫性のない状態になる可能性があることです。また、スレッドの安全性を確保するために、多くの余分な労力が必要になります。

より良い代替案は、ビルダー パターンを使用することです。

public class Pizza {
  private int size;
  private boolean cheese;
  private boolean pepperoni;
  private boolean bacon;

  public static class Builder {
    //required
    private final int size;

    //optional
    private boolean cheese = false;
    private boolean pepperoni = false;
    private boolean bacon = false;

    public Builder(int size) {
      this.size = size;
    }

    public Builder cheese(boolean value) {
      cheese = value;
      return this;
    }

    public Builder pepperoni(boolean value) {
      pepperoni = value;
      return this;
    }

    public Builder bacon(boolean value) {
      bacon = value;
      return this;
    }

    public Pizza build() {
      return new Pizza(this);
    }
  }

  private Pizza(Builder builder) {
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.bacon;
  }
}

Pizza は不変であり、パラメータ値はすべて 1 か所にあることに注意してください。Builder の setter メソッドは Builder オブジェクトを返すため、連鎖させることができます

Pizza pizza = new Pizza.Builder(12)
                       .cheese(true)
                       .pepperoni(true)
                       .bacon(true)
                       .build();

これにより、書きやすく、読みやすく、理解しやすいコードになります。この例では、ビルド メソッドを変更して、ビルダーから Pizza オブジェクトにコピーされた後にパラメータをチェックし、無効なパラメータ値が指定された場合は IllegalStateException をスローするようにできます。このパターンは柔軟性があり、将来的にパラメータを追加するのも簡単です。これは、コンストラクターに 4 つまたは 5 つ以上のパラメータがある場合にのみ役立ちます。とはいえ、将来的にパラメータを追加する可能性があると思われる場合は、最初から行う価値があるかもしれません。

このトピックについては、Joshua Bloch 著の『 Effective Java, 2nd Edition』から多くの情報を得ました。このパターンやその他の効果的な Java プラクティスについて詳しく知りたい場合は、ぜひこの本をお読みください。

おすすめ記事