ビルダーパターン
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を通じてのみ作成できます。このパターンは、オブジェクトに多くのオプションのフィールドがある場合に真価を発揮し、長いパラメータリストよりもコードを読みやすく、エラーが発生しにくくします。
チャレンジ
簡単Builderパターンを使用してピザ注文システムを構築しましょう!すべての可能なトッピングやオプションのために数十のパラメータを受け取るコンストラクタを扱う代わりに、ピザのカスタマイズをクリーンで読みやすくする流暢なビルダーを作成します。
コードは2つのファイルに分けて構成します:
Pizza.java: 構築にBuilderパターンを使用するPizzaクラスを作成します。ピザには以下のフィールドが必要です:size(String) - 必須、ピザのサイズを表しますcheese(boolean) - オプション、デフォルトは falsepepperoni(boolean) - オプション、デフォルトは falsemushrooms(boolean) - オプション、デフォルトは falsePizzaのコンストラクタは 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つの入力を受け取ります。
例えば、入力が Large、yes、no、yes の場合、出力は 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: ピザをビルドし、その説明を出力する
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造