Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

書籍 Effective Java | 数多くのコンストラクタパラメータに直面した時にはビルダーを検討する

パンくず

Effective Java
数多くのコンストラクタパラメータに直面した時にはビルダーを検討する

概要

数多くのコンストラクタパラメータに直面した時にはビルダーを検討する

想定されるケース

必須項目、オプション項目を含む多数の項目を扱うクラスを作成する場合
初期化の処理が煩雑になる。

解法1 テレスコーピングコンストラクタ

全項目指定した場合のコンストラクタを用意し、オプションを省略する場合のコンストラクタ
オプション項目だけ初期値を設定した上で全項目用のコンストラクタをチェーンして呼び出す。
オプション項目が増えれば増えるほどコンストラクタの数が増えることや、
予備元が値を指定する場合に、「引数のN番目はこの項目」という情報を覚える必要があり
利用や保守が困難。

テレスコーピングコンストラクタ・パターン サンプルコード

public class Hoge
  private final String hoge;// 必須
  private final String hige;// オプション
  private final String hage;// オプション

  public Hoge(String hoge,String hige,String hage) {
    this.hoge = hoge;
    this.hige = hige;
    this.hage = hage;
  }
  
  public Hoge(String hoge,String hige) {
    Hoge(hoge,hige,"初期値");
  }
  
  public Hoge(String hoge) {
    Hoge(hoge,"初期値","初期値");
  }

解法2 JavaBeansパターン

コンストラクタはデフォルトコンストラクタを使用し、
残りの項目はsetter経由で設定すること。
この場合、利用側が初期化処理を誤る可能性が大きくなる。

解法3 ビルダーを利用したパターン

生成手順をビルダーにまとめます。
この際に、各メンバーの名称そのままのメソッドから値を設定することで
どの項目を設定しているのかわかりやすくします。
さらにビルダーのインスタンスを返却し、流れるようなインターフェースを実装することで
可読性を高めます。

ビルダーを利用したパターンのサンプルコード

package effective.creation.chapter2;

public class Hoge {
  public static class HogeBuilder {
    // 必須
    private String hoge = "";

    // オプション
    private String hige = "初期値";
    private String hage = "初期値";

    public HogeBuilder(String hoge) {
      this.hoge = hoge;
    }

    public Hoge build() {
      return new Hoge(this);

    }

    public HogeBuilder hage(String hage) {
      this.hage = hage;
      return this;
    }

    public HogeBuilder hige(String hige) {
      this.hige = hige;
      return this;
    }

    public HogeBuilder hoge(String hoge) {
      this.hoge = hoge;
      return this;
    }
  }

  private String hoge = "";
  private String hige = "";
  private String hage = "";

  private Hoge(HogeBuilder hogeBuilder) {
    this.hoge = hogeBuilder.hoge;
    this.hige = hogeBuilder.hige;
    this.hage = hogeBuilder.hage;
  }

  @Override
  public String toString() {
    return "hoge:" + hoge + "\nhige:" + hige + "\nhage:" + hage + "\n";
  }

}

呼び出しコード

package effective.creation.chapter2;

public class HogeUser {

  public static void main(String[] args) {
    Hoge hogeAll = new Hoge.HogeBuilder("hoge").hige("hige").hage("hage").build();
    System.out.println(hogeAll);
    Hoge hogeHige = new Hoge.HogeBuilder("hoge").hige("hige").build();
    System.out.println(hogeHige);
    Hoge hogeHage = new Hoge.HogeBuilder("hoge").hage("hage").build();
    System.out.println(hogeHage);
  }
}

出力

hoge:hoge
hige:hige
hage:hage

hoge:hoge
hige:hige
hage:初期値

hoge:hoge
hige:初期値
hage:hage