キーワード†
- インスタンス
- 生成
- パラメータ
- 生成
何か†
組み立て屋さん
インスタンスを生成するために必要なパラメータをもつビルダークラスを別途設けます。このビルダークラスのオブジェクトはパラメータ(ビルダーの属性)を使用することで対象のインスタンスを生成して完全な状態にします。
Effective JavaでいうところのビルダーパターンとGoFが提唱するビルダーパータンは別のものです。ここでは前者を挙げています。
後者の特徴はDirectorがインスタンス生成のための手順をもっていることです。単に複数のパラメータが必要であるということだけではない手順です。調理法が定まっていて食材を変えることができるイメージです。
なぜか†
引数が多すぎるとコードの見通しが悪くなります。コンストラクタについても同じことが言えます。ビルダーにインスタンスの生成責務を預けることでコンストラクタの引数が多くなり過ぎる問題を解決できます。また、インスタンスを生成するためのインタフェースを特定しませんから、ビルダーがパラメータに応じて柔軟にインスタンスの生成パターンを変更することができます。
- コンストラクタの過剰なパラメータ数を回避
- クライアント側から生成パターンを特定しない
デフォルトコンストラクタでインスタンスを生成して属性を後からセットする手段もあります。JavaBeansパターンです。この方法ではクライアントが注意深くインスタンスを生成しなければなりません。対象のオブジェクトがメソッド実行の際に完全な状態であることを自身でチェックすることはできます。しかし対象のクラスの責務が大きくなり過ぎて見通しが悪くなります。本来のドメインモデルにおける債務に集中できなくなってしまいます。
- 責務(: 完全な状態であることのチェック)を分離
どのように†
たとえば、Userクラスのインスタンスを生成するためのUser.Builderクラスを設けます。
User { Builder { // required private name; // optional private gender; public Builder(name) { this.name = name; } public setGender(gender) { this.gender = gender; return this; } public build() { /* * ここでパラメータの整合性チェックをする * (チェックエラーの場合IllegalArgumentExceptionを投げるなど) */ User user = new User(); user.name = this.name; user.gender = this.gender; return user; } } private name, gender; private User(){} }
クライアントはUser.Builderを使ってUserクラスのインスタンスを得ます。
Client { do() { User user = new User.Builder("fukuchi").setGender("male").build(); } }