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 プラクティスについて詳しく知りたい場合は、ぜひこの本をお読みください。