1. 序章

Builderデザインパターンは、最も広く使用されている作成パターンの1つです。 複雑なオブジェクトを作成するのに役立ちます。

ビルダーを手作業で作成するのは面倒でエラーが発生しやすくなります。 したがって、可能な限り、専用のツールを使用してそれらを自動生成する必要があります。

このチュートリアルでは、 IntelliJIDEでビルダークラスを自動的に作成するさまざまな方法について説明します。 IntelliJがすぐに提供する組み込み機能と、サードパーティのプラグインについて見ていきます。

2. 初期設定

この記事全体を通して、執筆時点で最新のリリースであるIntelliJIDEAコミュニティエディションのバージョン2019.1.3を使用します。 ただし、例に示されているすべての手法は、他のバージョンのIDEAでも正常に機能するはずです。

ビルダーを生成するBookクラスの定義から始めましょう。

public class Book {
    private String title;
    private Author author;
    private LocalDate publishDate;
    private int pageCount;

    // standard constructor(s), getters and setters
}

3. IntelliJの組み込み機能の使用

IntelliJの組み込みツールを使用してBookクラスのビルダーを生成するには、適切なコンストラクターが必要です。

1つ作成しましょう:

public Book(String title, Author author, LocalDate publishDate, int pageCount) {
    this.title = title;
    this.author = author;
    this.publishDate = publishDate;
    this.pageCount = pageCount;
}

これで、ビルダーを作成する準備が整いました。 したがって、作成したコンストラクターにカーソルを置き、 Ctrl + Alt + Shift + T (PCの場合)を押して Refactor This ポップアップを開き、 ConstructorwithBuilderを選択します。 リファクタリング:

名前やターゲットパッケージなど、ビルダークラスのいくつかのオプションをさらに調整できます。

その結果、BookBuilderクラスが生成されました。

public class BookBuilder {
    private String title;
    private Author author;
    private LocalDate publishDate;
    private int pageCount;

    public BookBuilder setTitle(String title) {
        this.title = title;
        return this;
    }

    public BookBuilder setAuthor(Author author) {
        this.author = author;
        return this;
    }

    public BookBuilder setPublishDate(LocalDate publishDate) {
        this.publishDate = publishDate;
        return this;
    }

    public BookBuilder setPageCount(int pageCount) {
        this.pageCount = pageCount;
        return this;
    }

    public Book createBook() {
        return new Book(title, author, publishDate, pageCount);
    }
}

3.1. カスタムセッタープレフィックス

ビルダークラスのセッターメソッドにwithプレフィックスを使用するのが一般的な方法です。

デフォルトのプレフィックスを変更するには、オプションウィンドウの右上隅にある[Rename SettersPrefix]アイコンを選択する必要があります

3.2. 静的インナービルダー

私たちの中には、Effective JavaのJoshuaBlochによって説明されているように、静的内部クラスとしてビルダーを実装することを好む人もいます。

この場合、IntelliJのコンストラクターをBuilder に置き換える機能を使用して、これを実現するためにいくつかの追加手順を実行する必要があります。

まず、空の内部クラスを手動で作成し、コンストラクターをプライベートにする必要があります。

public class Book {

    private String title;
    private Author author;
    private LocalDate publishDate;
    private int pageCount;

    public static class Builder {
        
    }

    private Book(String title, Author author, LocalDate publishDate, int pageCount) {
        this.title = title;
        this.author = author;
        this.publishDate = publishDate;
        this.pageCount = pageCount;
    }

    // standard getters and setters
}

さらに、オプションウィンドウで既存のを使用を選択し、新しく作成したクラスをポイントする必要があります。

 

4. InnerBuilderプラグインの使用

InnerBuilder プラグインを使用して、Bookクラスのビルダーを生成する方法を見てみましょう。

プラグインをインストールしたら、 Alt + Insert (PCの場合)を押して Builder…オプションを選択すると、Generateポップアップを開くことができます。

または、 Alt + Shift + B (PCの場合)を押して、InnerBuilderプラグインを直接呼び出すこともできます。

ご覧のとおり、生成されたビルダーをカスタマイズするために選択できるオプションがいくつかあります。

すべてのオプションがオフになっているときに生成されるビルダーを見てみましょう。

public static final class Builder {
    private String title;
    private Author author;
    private LocalDate publishDate;
    private int pageCount;

    public Builder() {
    }

    public Builder title(String val) {
        title = val;
        return this;
    }

    public Builder author(Author val) {
        author = val;
        return this;
    }

    public Builder publishDate(LocalDate val) {
        publishDate = val;
        return this;
    }

    public Builder pageCount(int val) {
        pageCount = val;
        return this;
    }

    public Book build() {
        return new Book(this);
    }
}

InnerBuilderプラグインは、デフォルトで静的内部クラスとしてビルダーを実装します。

5. BuilderGeneratorプラグインの使用

最後に、 BuilderGeneratorがどのように機能するかを見てみましょう。

同様に、InnerBuilderの場合は、 Alt + Insert (PCの場合)を押して Builder オプションを選択するか、 Alt + Shift +Bショートカットを使用できます。

ご覧のとおり、BookBuilderをカスタマイズするために選択できるオプションは3つあります。

すべてのオプションをオフのままにして、生成されたビルダークラスを見てみましょう。

public final class BookBuilder {
    private String title;
    private Author author;
    private LocalDate publishDate;
    private int pageCount;

    private BookBuilder() {
    }

    public static BookBuilder aBook() {
        return new BookBuilder();
    }

    public BookBuilder withTitle(String title) {
        this.title = title;
        return this;
    }

    public BookBuilder withAuthor(Author author) {
        this.author = author;
        return this;
    }

    public BookBuilder withPublishDate(LocalDate publishDate) {
        this.publishDate = publishDate;
        return this;
    }

    public BookBuilder withPageCount(int pageCount) {
        this.pageCount = pageCount;
        return this;
    }

    public Book build() {
        Book book = new Book();
        book.setTitle(title);
        book.setAuthor(author);
        book.setPublishDate(publishDate);
        book.setPageCount(pageCount);
        return book;
    }
}

作成されたビルダークラスをカスタマイズするためにBuilderGeneratorプラグインが提供する最初のオプション– 内部ビルダー–はかなり自明です。

ただし、他の2つはもっと興味深いので、次のセクションでそれらについて説明します。

5.1. ‘but’メソッドオプション

このオプションを選択すると、プラグインは but()メソッドをBookBuilderクラスに追加します。

public BookBuilder but() {
    return aBook().withTitle(title).withAuthor(author)
      .withPublishDate(publishDate).withPageCount(pageCount);
}

ここで、同じ著者、同じページ数で、タイトルと発行日が異なる3冊の本を作成するとします。 共通のプロパティがすでに設定されているベースビルダーを作成し、but()メソッドを使用して、そこから新しいBookBuilder(および後でBooks)を作成する場合があります。

例を見てみましょう:

BookBuilder commonBuilder = BookBuilder.aBook().withAuthor(johnDoe).withPageCount(123);

Book my_first_book = commonBuilder.but()
  .withPublishDate(LocalDate.of(2017, 12, 1))
  .withTitle("My First Book").build();

Book my_second_book = commonBuilder.but()
  .withPublishDate(LocalDate.of(2018, 12, 1))
  .withTitle("My Second Book").build();

Book my_last_book = commonBuilder.but()
  .withPublishDate(LocalDate.of(2019, 12, 1))
  .withTitle("My Last Book").build();

5.2. シングルフィールドオプションを使用する

このオプションを選択すると、生成されたビルダーは、ブックのすべてのプロパティではなく、作成されたBookオブジェクトへの参照を保持します。

public final class BookBuilder {
    private Book book;

    private BookBuilder() {
        book = new Book();
    }

    public static BookBuilder aBook() {
        return new BookBuilder();
    }

    public BookBuilder withTitle(String title) {
        book.setTitle(title);
        return this;
    }

    public BookBuilder withAuthor(Author author) {
        book.setAuthor(author);
        return this;
    }

    public BookBuilder withPublishDate(LocalDate publishDate) {
        book.setPublishDate(publishDate);
        return this;
    }

    public BookBuilder withPageCount(int pageCount) {
        book.setPageCount(pageCount);
        return this;
    }

    public Book build() {
        return book;
    }
}

これは、特定の状況で役立つビルダークラスを作成するための少し異なるアプローチです。

6. 結論

このチュートリアルでは、IntelliJでビルダークラスを生成するさまざまな方法を検討しました。

通常、これらの種類のツールを使用してビルダーを自動的に生成することをお勧めします。 私たちが提示した各オプションには、長所と短所があります。 私たちが実際にどちらのアプローチを選択するかは、むしろ好みと個人の好みの問題です。