LoginSignup
0
1

More than 1 year has passed since last update.

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

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

0
1
0

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
  3. You can use dark theme
What you can do with signing up
0
1