search
LoginSignup
1

posted at

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

これは何?

Effective Java 第3版を読んで自分なりにかみ砕いた内容を記事に落としていきます。
良いコードを書くための選択肢の一つになれば最高なので、頑張ります。
※読み進める中で知識のアップデート等あれば都度更新いたします。

問題提起

前の記事で紹介したstaticファクトリメソッドやコンストラクタは共通の課題がある。
「多くの必須ではないパラメータ(オプションパラメータ)に上手く対応できない」

この問題にうまく対応する方法が Builderパターン である。

選択肢①(あまり良くない)

テレスコーピング・コンストラクタが使われたりするらしい。。。

//テレスコーピング・コンストラクタ
public class Hoge {
  private final int 必須パラメータ1
  private final int 必須パラメータ2
  private final int オプションパラメータ1
  private final int オプションパラメータ2
  private final int オプションパラメータ3

  public コンストラクタ(int 必須1, int 必須2) {
    this(必須1, 必須2, 0);
  }

  public コンストラクタ(int 必須1, int 必須2, int オプション1) {
    this(必須1, 必須2, オプション1)
  }

  //同じ要領でパラメータを増やしたコンストラクタを作成する。
}

この場合、オプションパラメータすべてを設定しようとすると、

  • コードを書くのが大変になる
  • コードを読むのはもっと大変になる(どのパラメータが何に対応しているか)

選択肢②(あまり良くない)

JavaBeanパターンなるものがあるらしい。
→パラメータなしのコンストラクタを呼び出す。その後、パラメータを設定するためのセッターを呼び出す。

public class Hoge {
  //(あれば)パラメータを初期化
  private final int 必須パラメータ1 = -1
  private final int 必須パラメータ2 = -1
  private final int オプションパラメータ1 = 0
  private final int オプションパラメータ2 = 0
  private final int オプションパラメータ3 = 0

  public Hoge() { }

  //セッター
  public void set必須1(int value) { 必須パラメータ1 = value}
  public void set必須2(int value) { 必須パラメータ2 = value}
  //以下オプションパラメータもセッターを作成
}

この場合、テレスコーピング・コンストラクタが持っていた欠点は無くなった!!
セッターに名前がついているのでコードを書きやすいし、読みやすくなる。

しかし、これも重大な問題がある。。。

  • オブジェクトの生成過程で不整合な状態になる
  • 不変クラスになる可能性がなくなる
    (この欠点については、不変クラスなどで検索してみてください。私も絶賛勉強中)

選択肢③(本題)

やっと出てきました本題のBuilderパターンです。
Builderパターンの概要は以下のような感じ

  • 必須パラメータをすべて持つコンストラクタかstaticファクトリメソッドを呼び出す
  • 必要なオプションパラメータを設定するためのセッターを呼び出す
  • パラメータを持たないbuildメソッドを呼び出す

具体的なコードは以下

public class Hoge() {
  private final int 必須1
  private final int 必須2
  private final int オプション1
  private final int オプション2
  private final int オプション3
  private final int オプション4

  public static class Builder {
    //必須パラメータ
    private final int 必須1
    private final int 必須2

    //オプションパラメータ - デフォルト値に初期化
    private final int オプション1 = 0;
    private final int オプション2 = 0;
    private final int オプション3 = 0;
    private final int オプション4 = 0;

    public Builder(int 必須1, int 必須2) {
      this.必須1 = 必須1;
      this.必須2 = 必須2
    }

    public Builder オプション1(int value) {
      オプション1 = value;
      return this;
    }
    public Builder オプション2(int value) {
      オプション2 = value;
      return this;
    }
    public Builder オプション3(int value) {
      オプション3 = value;
      return this;
    }
    public Builder オプション4(int value) {
      オプション4 = value;
      return this;
    }

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

  private Hoge(Builder builder) {
    必須1 = builder.必須1;
    必須2 = builder.必須2;
    オプション1 = builder.オプション1;
    オプション2 = builder.オプション2;
    オプション3 = builder.オプション3;
    オプション4 = builder.オプション4;
  }
}

セッターメソッドはBuilder自身をreturnするので、オブジェクト生成時は

Hoge hoge = new Hoge.Builder(4, 29).オプション1(38).オプション2(32).オプション3(23).オプション4(38).build()

となる(きれいなコードの完成!!)

Builderパターンのより適したものについては次の記事で書きます。(絶賛勉強中)
よろしくお願いします!!!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1