作り方
クラス名
以下のいずれかがよく使われます。
- 作りたいクラス +
Builder
- 例: DateTimeFormatter を作る DateTimeFormatterBuilder
- 作りたいクラスの内部クラスで
Builder
- 例: HttpUrl を作る HttpUrl.Builder
ファクトリー、コンストラクタ
一般的には引数なしのコンストラクタが使われます。 DbSetupのOperationsのように、staticメソッドを用意しているものもありますが、 柔軟性でなく、流れるようなインタフェースにするために使われています。
メソッド
setterを実装しますが、
流れるようなインタフェースを考慮して、set
なんとかという名前にはしません1。
ただし、以下のような使い分けをする場合はset
を付けます。
addXXX
: 値を追加するものsetXXX
: 値を新規設定するもの- HttpUrl.Builder#setEncodedQueryParameterのように、「削除してから追加」する場合が該当します。
最後に追加していくStringBuilderなどでは、append
系の命名が使われることが多いです。
最後のメソッドはbuild()
のことが多いです。
例外処理
- setter: IllegalArgumentException
- build(): IllegalStateException
- 必要なパラメータを渡していない場合
チェック例外は流れるようなインタフェースと相性が悪いので、避けたほうがいいです。 必要なときは、ValueObject(URIなど)を渡すようにしたらいいと思います。
Mail = new MailBuilder()
.to("[email protected]") // ここでチェック例外を投げたい場合
.build();
ここでメールアドレスをセットするときにチェック例外を投げたい場合は以下のようにします。
MailAddress mailTo;
try {
mailTo = MailAddress.of("[email protected]");
} catch (MailAddressException e) {
// 例外処理
}
Mail = new MailBuilder()
.to(mailTo)
.build();
ビルダー自体のカスタマイズ
簡単なものなら、コンストラクタの引数に持つのが良いかと思います。 Builder自体を取り替えたい場合は、 DocumentBuilderFactoryのようにさらにファクトリを定義する例もありますが、 正直冗長かなと思います。setNamespaceAwareしか使ったことないし。。。
テンプレート
public final class ColorBuilder {
private String color;
public ColorBuilder() {
}
public ColorBuilder color(String color) {
this.color = color;
return this;
}
public Color build() {
return new Color(this.color);
}
}