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