0Pricing
Java Academy · レッスン

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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Singleton:スレッドセーフな実装
  2. Factory Method パターン
  3. 製品ファミリーのための Abstract Factory
  4. Fluent API を使った Builder パターン
← Java Academyに戻る