Fluent API を使った Builder パターン
fluent builder で複雑なオブジェクトを段階的に構築し、コンストラクターの肥大化を避けます。
「Fluent API を使った Builder パターン」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
テレスコーピングコンストラクターの問題
クラスに多くのオプションパラメーターがあると、2個用、3個用、4個用というようにコンストラクターが増えていきます。Builder パターンは、流れるように記述できる段階的な設定 API によってこの問題を解決します。
// Without builder — hard to read:
Pizza p = new Pizza("large", "thin", true, false, true, false, "mozzarella");Builder の基本構造
静的なネストクラス Builder を作成します。外側のクラスには、Builder を受け取る private コンストラクターを用意します。Builder の各セッターは、メソッドを連続して呼び出せるように this を返します。
public final class Pizza {
private final String size, crustType, cheese;
private final boolean extraSauce, pepperoni;
private Pizza(Builder b) {
this.size = b.size; this.crustType = b.crustType;
this.cheese = b.cheese; this.extraSauce = b.extraSauce;
this.pepperoni = b.pepperoni;
}
public static class Builder {
private final String size;
private String crustType = "regular", cheese = "mozzarella";
private boolean extraSauce, pepperoni;
public Builder(String size) { this.size = size; }
public Builder crustType(String c) { this.crustType = c; return this; }
public Builder cheese(String c) { this.cheese = c; return this; }
public Builder extraSauce() { this.extraSauce = true; return this; }
public Builder pepperoni() { this.pepperoni = true; return this; }
public Pizza build() { return new Pizza(this); }
}
}Fluent API の利用
Builder のコードは文章のように読めます。必須パラメーターはコンストラクターに渡し、オプションのパラメーターはメソッド呼び出しで指定します。最後に build() を呼び出すと、不変オブジェクトが生成されます。
Pizza p = new Pizza.Builder("large")
.crustType("thin")
.extraSauce()
.pepperoni()
.build();
System.out.println(p);build() でのバリデーション
オブジェクトを生成する前に、build() の内部にバリデーションロジックを追加します。無効な組み合わせに対しては、IllegalStateException または IllegalArgumentException をスローします。
public Pizza build() {
if (size == null || size.isBlank())
throw new IllegalArgumentException("Size required");
if (extraSauce && crustType.equals("stuffed"))
throw new IllegalStateException("No extra sauce on stuffed crust");
return new Pizza(this);
}不変オブジェクトのための Builder
外側のクラスは Builder から一度に生成されるため、すべてのフィールドを final にできます。その結果、完全に不変でスレッドセーフなオブジェクトを作成できます。
public final class Address {
private final String street, city, country;
private final String postalCode;
private Address(Builder b) { ... } // all finals
// no setters — immutable!
}自己型を使ったジェネリック Builder
継承階層では、再帰的なジェネリック型パラメーター(SELF extends Builder<SELF>)を使います。これにより、サブクラスの Builder が、連続呼び出しされるメソッドからサブクラス型を返せます。
public abstract static class Builder<SELF extends Builder<SELF>> {
String name;
@SuppressWarnings("unchecked")
public SELF name(String n) { this.name = n; return (SELF) this; }
public abstract Vehicle build();
}Lombok @Builder
Lombok の @Builder は、Builder に必要な仕組み全体をコンパイル時に生成します。フィールドのデフォルト値には @Builder.Default を、コレクションには @Singular を使用します。
@Builder
public class Report {
private final String title;
@Builder.Default private final int pageCount = 1;
@Singular private final List<String> authors;
}
// Usage:
Report r = Report.builder().title("Q4").author("Alice").author("Bob").build();JDK の Builder
多くの JDK クラスが Builder スタイルの API を使用しています。例として StringBuilder、HttpRequest.newBuilder()、ProcessBuilder、Stream.Builder があります。このパターンを見分けられるようになりましょう。
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.header("Accept", "application/json")
.GET()
.build();Builder と Factory の比較
オブジェクトに多くのパラメーターが必要で、段階的な設定を行う場合は Builder を使います。すべてのバリエーションが単純で、1回の呼び出しで生成できる場合は Factory を使います。
テストデータのための Builder
Builder はテストで特に力を発揮します。ヘルパーで基本の Builder を作成し、各テストケースに関係するフィールドだけを上書きできます。これにより、テストの重複を避けながら読みやすく保てます。
User defaultUser() { return new User.Builder("test@example.com").name("Test User").build(); }
User adminUser() { return new User.Builder("admin@example.com").name("Admin").role(ADMIN).build(); }スレッドセーフティ
Builder 自体はスレッドセーフではないため、複数のスレッドで1つの Builder を共有しないでください。そこから生成されるプロダクトは、すべてのフィールドが final で、可変オブジェクトを共有していなければ、不変かつスレッドセーフにできます。
確認問題
Builder のメソッドを「fluent」にするものは何ですか。
まとめ
Builder はテレスコーピングコンストラクターの問題を解決します。静的なネストクラス Builder を使用し、各セッターから this を返し、build() でバリデーションを行って、不変オブジェクトを生成します。Lombok の @Builder は定型コードを自動化します。
よくある質問
「Fluent API を使った Builder パターン」レッスンは無料ですか?
はい。「Fluent API を使った Builder パターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「Fluent API を使った Builder パターン」で何を学びますか?
fluent builder で複雑なオブジェクトを段階的に構築し、コンストラクターの肥大化を避けます。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「Fluent API を使った Builder パターン」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Singleton:スレッドセーフな実装
- Factory Method パターン
- 製品ファミリーのための Abstract Factory
- Fluent API を使った Builder パターン