Menu
Coddy logo textTech

ビルダーパターン

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

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

必須フィールド(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 constructor が private であることに注目してください。オブジェクトは Builder を通してのみ作成できます。このパターンは、オブジェクトに多数の optional フィールドがある場合に特に効果を発揮し、長い parameter リストを使うよりもコードが読みやすく、エラーが発生しにくくなります。

challenge icon

チャレンジ

簡単

Builder Patternを使用してピザ注文システムを構築しましょう!すべてのトッピングやオプションに対応する数十個のパラメータを受け取るconstructorを扱う代わりに、ピザのカスタマイズをすっきりと読みやすくするfluent builderを作成します。

コードを2つのファイルに分けて整理します。

  • Pizza.java: Builder Patternを使用して構築するPizza classを作成します。Pizzaには次のfieldsを持たせます。

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

    cheese (boolean) - optional。デフォルトはfalseです

    pepperoni (boolean) - optional。デフォルトはfalseです

    mushrooms (boolean) - optional。デフォルトはfalseです

    Pizza constructorはprivateにし、parameterとしてPizzaBuilderのみを受け取り、builderのすべての値をPizzaのfieldsにコピーします。

    getDescription() methodを含め、次の形式のstringを返すようにします: [size] Pizza with: [toppings]。ここでtoppingsは、trueになっているトッピング(Cheese、Pepperoni、Mushrooms)をカンマ区切りで並べたlistです。トッピングが選択されていない場合、toppingsの部分はno toppingsとだけ表示します。

    次の内容を持つstaticなinner class PizzaBuilderを作成します。

    • 必須のsize parameterを受け取るconstructor
    • それぞれ対応するbooleanをtrueに設定し、chainingのためにthisを返すcheese()pepperoni()mushrooms() methods
    • 新しいPizzaを返すbuild() method
  • Main.java: Pizza builderを実際に動作させてみましょう!4つのinputを受け取ります。ピザのサイズ(String)と、cheese、pepperoni、mushroomsをそれぞれ追加するかどうかを示す3つのyes/no値(Strings)です。

    指定されたsizeでPizzaBuilderを作成します。次に、それぞれのyes/no inputに基づいて、適切なトッピングmethodsをchainします。inputが"yes"の場合はそのトッピングmethodを呼び出し、"no"の場合はスキップします。最後にbuild()を呼び出してPizzaを作成します。

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

inputは次の順番で4つ受け取ります: size (String)、cheeseを追加 (String: "yes" または "no")、pepperoniを追加 (String: "yes" または "no")、mushroomsを追加 (String: "yes" または "no")。

たとえば、inputがLargeyesnoyesの場合、出力は次のようになります: Large Pizza with: Cheese, Mushrooms

Builder Patternを使うと、可能性ごとに別々のconstructorを用意する必要なく、トッピングを自由に組み合わせてPizzaを構築できることに注目してください!

自分で試してみよう

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: 指定されたサイズでPizzaBuilderを作成する
        // TODO: yes/noの入力に基づいてトッピングメソッドをチェーンする
        // TODO: ピザをビルドしてその説明を出力する
        
    }
}
quiz icon腕試し

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

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

自分で練習してみよう: Javaオンラインコンパイラ