Menu
Coddy logo textTech

ビルダーパターン

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 67/87。

ビルダーパターン(Builder Pattern)は、多くのオプションのパラメータを持つ複雑なオブジェクトの構築という、一般的な問題を解決する生成に関するデザインパターンです。複数のコンストラクタを作成したり、使用しないパラメータに null を渡したりする代わりに、ビルダーを使用すると、オブジェクトをステップバイステップで構築できます。

必須フィールド(name、email)とオプションのフィールド(age、phone、address)を持つUserオブジェクトを作成することを考えてみましょう。Builderパターンを使用しない場合、テレスコーピング・コンストラクタや、多くのパラメータを持つ煩雑なコンストラクタが必要になります。Builderパターンは、よりクリーンなアプローチを提供します:

public class User {
    private final String name;    // 必須
    private final String email;   // 必須
    private final int age;        // 任意
    private final String phone;   // 任意
    
    private User(UserBuilder builder) {
        this.name = builder.name;
        this.email = builder.email;
        this.age = builder.age;
        this.phone = builder.phone;
    }
    
    public static class UserBuilder {
        private final String name;
        private final String email;
        private int age;
        private String phone;
        
        public UserBuilder(String name, String email) {
            this.name = name;
            this.email = email;
        }
        
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
        
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public User build() {
            return new User(this);
        }
    }
}

Builderのメソッドはthisを返すため、オブジェクトを構築するための流暢で読みやすい手法であるメソッドチェーンが可能になります:

User user = new User.UserBuilder("Alice", "alice@email.com")
    .age(25)
    .phone("555-1234")
    .build();

Userコンストラクタがprivateであることに注目してください。オブジェクトはBuilderを通じてのみ作成できます。このパターンは、オブジェクトに多くのオプションのフィールドがある場合に真価を発揮し、長いパラメータリストよりもコードを読みやすく、エラーが発生しにくくします。

challenge icon

チャレンジ

簡単

Builderパターンを使用してピザ注文システムを構築しましょう!すべての可能なトッピングやオプションのために数十のパラメータを受け取るコンストラクタを扱う代わりに、ピザのカスタマイズをクリーンで読みやすくする流暢なビルダーを作成します。

コードは2つのファイルに分けて構成します:

  • Pizza.java: 構築にBuilderパターンを使用する Pizza クラスを作成します。ピザには以下のフィールドが必要です:

    size (String) - 必須、ピザのサイズを表します

    cheese (boolean) - オプション、デフォルトは false

    pepperoni (boolean) - オプション、デフォルトは false

    mushrooms (boolean) - オプション、デフォルトは false

    Pizza のコンストラクタは private にし、パラメータとして PizzaBuilder のみを受け取り、ビルダーからピザのフィールドにすべての値をコピーするようにします。

    getDescription() メソッドを含めます。このメソッドは、[size] Pizza with: [toppings] という形式の文字列を返します。ここで toppings は、true であるトッピング(Cheese、Pepperoni、Mushrooms)をカンマで区切ったリストです。トッピングが選択されていない場合、トッピングの部分は単に no toppings と表示される必要があります。

    以下の内容を持つ static な内部クラス PizzaBuilder を作成します:

    • 必須の size パラメータを受け取るコンストラクタ
    • それぞれの boolean を true に設定し、メソッドチェーンのために this を返す cheese()pepperoni()、および mushrooms() メソッド
    • 新しい Pizza を返す build() メソッド
  • Main.java: ピザビルダーの動作を実演します!4つの入力を受け取ります:ピザのサイズ (String)、およびチーズ、ペパロニ、マッシュルームをそれぞれ追加するかどうかを示す3つの yes/no 値 (String) です。

    指定されたサイズで PizzaBuilder を作成します。次に、各 yes/no 入力に基づいて、適切なトッピングメソッドをチェーンさせます。入力が "yes" の場合はそのトッピングメソッドを呼び出し、"no" の場合はスキップします。最後に、build() を呼び出してピザを作成します。

    完成したピザに対して getDescription() を呼び出した結果を出力します。

サイズ (String)、チーズの追加 (String: "yes" または "no")、ペパロニの追加 (String: "yes" または "no")、マッシュルームの追加 (String: "yes" または "no") の順に4つの入力を受け取ります。

例えば、入力が Largeyesnoyes の場合、出力は Large Pizza with: Cheese, Mushrooms となります。

Builderパターンを使用することで、それぞれの可能性に対して個別のコンストラクタを必要とせずに、トッピングの任意の組み合わせでピザを構築できることに注目してください!

チートシート

Builder パターンは、多くのオプションパラメータを持つ複雑なオブジェクトを構築するための生成に関するデザインパターンです。オブジェクトを段階的に構築することで、テレスコーピングコンストラクタや長いパラメータリストを回避します。

構造

このパターンは以下で構成されます:

  • ビルダーのみを受け取るプライベートコンストラクタを持つクラス
  • オブジェクトを構築する静的内部 Builder クラス
  • メソッドチェーンのために this を返す Builder メソッド
  • 最終的なオブジェクトを作成する build() メソッド

実装例

public class User {
    private final String name;    // 必須
    private final String email;   // 必須
    private final int age;        // オプション
    private final String phone;   // オプション
    
    private User(UserBuilder builder) {
        this.name = builder.name;
        this.email = builder.email;
        this.age = builder.age;
        this.phone = builder.phone;
    }
    
    public static class UserBuilder {
        private final String name;
        private final String email;
        private int age;
        private String phone;
        
        public UserBuilder(String name, String email) {
            this.name = name;
            this.email = email;
        }
        
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
        
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public User build() {
            return new User(this);
        }
    }
}

メソッドチェーンを使用した使用例

User user = new User.UserBuilder("Alice", "alice@email.com")
    .age(25)
    .phone("555-1234")
    .build();

Builder パターンは、オブジェクトに多くのオプションフィールドがある場合に最適であり、多数のパラメータを持つコンストラクタと比較して、読みやすくメンテナンスしやすいコードを提供します。

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 入力を読み込む
        String size = scanner.nextLine();
        String addCheese = scanner.nextLine();
        String addPepperoni = scanner.nextLine();
        String addMushrooms = scanner.nextLine();
        
        // TODO: 指定された size で PizzaBuilder を作成する
        // TODO: yes/no の入力に基づいてトッピングのメソッドをチェーンさせる
        // TODO: ピザをビルドし、その説明を出力する
        
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン