JavaのBuilderパターン:明確なカスタムオブジェクトの作成
Builderデザインパターンの意図
JavaのBuilderデザインパターンは、基本的な生成パターンであり、複雑なオブジェクトを段階的に構築することを可能にします。複雑なオブジェクトの構築をその表現から分離し、同じ構築プロセスで異なる表現を作成できるようにします。
実世界の例を用いたBuilderパターンの詳細な説明
実世界の例
JavaのBuilderパターンは、オブジェクトの作成に多数のパラメーターが必要なシナリオで特に役立ちます。
デリでカスタマイズ可能なサンドイッチを構築していると想像してみてください。この文脈でのBuilderデザインパターンには、パンの種類、肉、チーズ、野菜、調味料など、サンドイッチの各構成要素を指定できるSandwichBuilderが含まれます。サンドイッチを最初から構築する方法を知る必要はなく、SandwichBuilderを使用して、必要な各コンポーネントを段階的に追加し、目的のサンドイッチを正確に手に入れることができます。この構築と最終製品の表現の分離により、指定されたコンポーネントに基づいて、同じ構築プロセスでさまざまな種類のサンドイッチを作成できます。
平易な言葉で
コンストラクターの汚染を避けながら、オブジェクトのさまざまなフレーバーを作成できます。オブジェクトの複数のフレーバーが存在する可能性がある場合に役立ちます。または、オブジェクトの作成に多くの手順が関与する場合に役立ちます。
Wikipediaによると
Builderパターンは、テレスコーピングコンストラクターアンチパターンへの解決策を見つけることを目的としたオブジェクト作成ソフトウェアのデザインパターンです。
それを踏まえて、テレスコーピングコンストラクターアンチパターンが何かを説明しましょう。ある時点で、私たちは皆、以下のようなコンストラクターに遭遇したことがあります。
public Hero(Profession profession,String name,HairType hairType,HairColor hairColor,Armor armor,Weapon weapon){
// Value assignments
}
ご覧のとおり、コンストラクターのパラメーターの数がすぐに圧倒的になり、その配置を理解するのが困難になります。さらに、将来さらにオプションを追加する場合、このパラメーターのリストは増え続ける可能性があります。これは、テレスコーピングコンストラクターアンチパターンとして知られています。
JavaでのBuilderパターンのプログラム例
このJava Builderパターンの例では、さまざまな属性を持つさまざまなタイプのHero
オブジェクトを構築します。
ロールプレイングゲームのキャラクタージェネレーターを想像してみてください。最も簡単な方法は、コンピューターにキャラクターを生成させることです。ただし、職業、性別、髪の色などのキャラクターの詳細を手動で選択したい場合は、すべての選択が完了すると、キャラクターの作成は段階的なプロセスになります。
より賢明なアプローチは、Builderパターンを使用することです。まず、作成したいHero
について考えてみましょう。
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
}
次に、Builder
があります。
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
次に、次のように使用できます。
public static void main(String[] args) {
var mage = new Hero.Builder(Profession.MAGE, "Riobard")
.withHairColor(HairColor.BLACK)
.withWeapon(Weapon.DAGGER)
.build();
LOGGER.info(mage.toString());
var warrior = new Hero.Builder(Profession.WARRIOR, "Amberjill")
.withHairColor(HairColor.BLOND)
.withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL).withWeapon(Weapon.SWORD)
.build();
LOGGER.info(warrior.toString());
var thief = new Hero.Builder(Profession.THIEF, "Desmond")
.withHairType(HairType.BALD)
.withWeapon(Weapon.BOW)
.build();
LOGGER.info(thief.toString());
}
プログラムの出力
16:28:06.058 [main] INFO com.iluwatar.builder.App -- This is a mage named Riobard with black hair and wielding a dagger.
16:28:06.060 [main] INFO com.iluwatar.builder.App -- This is a warrior named Amberjill with blond long curly hair wearing chain mail and wielding a sword.
16:28:06.060 [main] INFO com.iluwatar.builder.App -- This is a thief named Desmond with bald head and wielding a bow.
Builderパターンのクラス図

JavaでBuilderパターンを使用するタイミング
以下の場合にBuilderパターンを使用します
- Builderパターンは、複雑なオブジェクトの作成が必要なJavaアプリケーションに最適です。
- 複雑なオブジェクトを作成するアルゴリズムは、オブジェクトを構成するパーツとそれらがどのように組み立てられるかとは独立している必要があります。
- 構築プロセスでは、構築されたオブジェクトに対して異なる表現を許可する必要があります。
- 特に、製品を作成するために多くのステップが必要であり、これらのステップを特定の順序で実行する必要がある場合に役立ちます。
Builderパターン Javaチュートリアル
- JavaのBuilderデザインパターン(DigitalOcean)
- Builder(Refactoring Guru)
- JavaにおけるJoshua BlochのBuilderデザインパターンの探索(Java Magazine)
JavaにおけるBuilderパターンの実世界の応用
- 文字列を構築するためのJavaのStringBuilder。
- 変更可能な文字列オブジェクトを作成するために使用されるjava.lang.StringBuffer。
- Java.nio.ByteBuffer、およびFloatBuffer、IntBufferなどの同様のバッファー
- javax.swing.GroupLayout.Group#addComponent()
- UIコンポーネントを構築するIDEのさまざまなGUIビルダー。
- java.lang.Appendableのすべての実装
- Apache Camelビルダー
- Apache Commons Option.Builder
Builderパターンの利点とトレードオフ
利点
- 他の生成パターンと比較して、構築プロセスをより詳細に制御できます。
- オブジェクトの段階的な構築、構築手順の延期、または手順の再帰的な実行をサポートします。
- サブオブジェクトの複雑なアセンブリを必要とするオブジェクトを構築できます。最終製品は、それを構成するパーツとそれらのアセンブリプロセスから分離されています。
- 単一責任の原則。複雑な構築コードを製品のビジネスロジックから分離できます。
トレードオフ
- パターンでは複数の新しいクラスを作成する必要があるため、コード全体の複雑さが増加する可能性があります。
- 複数のビルダーオブジェクトを作成する必要があるため、メモリ使用量が増加する可能性があります。
関連するJavaデザインパターン
- 抽象ファクトリー:Builderと組み合わせて、複雑なオブジェクトの一部を構築するために使用できます。
- プロトタイプ:ビルダーは、多くの場合、プロトタイプからオブジェクトを作成します。
- ステップビルダー:ステップバイステップのアプローチを使用して複雑なオブジェクトを生成するBuilderパターンのバリエーションです。ステップビルダーパターンは、多数のオプションのパラメーターを持つオブジェクトを構築する必要があり、テレスコーピングコンストラクターアンチパターンを避けたい場合に適しています。