こんにちは!ぐちです。
久しぶりのデザインパターンの続編です。笑
イマイチこのデザインパターンのメリットがわかっていなくて、避けてたわけではないんですが、遠退いてしまっていました。
コードだけの列挙になるような気もしていますが、とりあえず今回は下記の記事七つ目をご紹介したいと思います。
Builderパターン
オブジェクトの生成制御のために使われることが多いそうです。ただのコンストラクタでも実現できるんですが、冗長的になるためにBuilderパターンがあるんですね。
コンストラクタ
では、早速コンストラクタで書かれたものを見てみましょう。
public class People { private String name; private Integer age; public People(String name, Integer age) { if (name == null || age == null) { throw new NullPointerException(); } this.name = name; this.age = age; } // getter, setter... public void sayGoodbye() { System.out.println("Good bye!!"); } }
上記の通り、コンストラクタのパラメータとして属性を受け取り、設定することはできますが、オプションが増えるとパラメータに大量のnullを渡すような冗長的な書き方になります。
public class Main { public static void main(String[] args) { People people = new People("John", 18); } }
GoF Builder
続いて、GoFのBuilderパターンを用いたコードをご紹介します。(※本当にご紹介するだけになります。。。よくわかっていません。)
public class People { private String name; private Integer age; // getter, setter... public void sayGoodbye() { System.out.println("Good bye!!"); } }
まずはオブジェクトクラスです。コンストラクタでパラメータを受け取る記述を省いた状態で、他は同じですね。
続いて、パラメータの設定を担っているDirectorクラスですね。
public class Director { private Builder builder; Director(Builder builder) { this.builder = builder; } public void construct() { builder.name("Tom"); builder.age(12); } }
続きまして、オブジェクトの生成ロジックを担うBuilderインターフェイスです。
public interface Builder { public void name(String name); public void age(Integer age); People getResult(); }
これを実装したPeopleBuilderクラスです。
public class PeopleBuilder implements Builder { private People people; public PeopleBuilder() { this.people = new People2(); } @Override public void name(String name) { people.setName(name); } @Override public void age(Integer age) { people.setAge(age); } @Override public People getResult() { if (people.getName() == null || people.getAge() == null) { throw new NullPointerException(); } return this.people; } }
setterやgetterにあたる自身を返却するメソッドを実装します。
最後に呼び出し元です。
public class Main { public static void main(String[] args) { Builder builder = new PeopleBuilder(); Director director = new Director(builder); director.construct(); builder.getResult().sayGoodbye(); } }
こうすることで
- 生成されるオブジェクト(People)と生成ロジック(Builder)が分離され、可読性が高まる。
- Builderの実装クラスを切り替えることで、生成するPeopleの制御が可能。
というメリットがあるそうです。
逆にデメリットとしては、
- interfaceや実装など、記述量が多くなる。
- 生成処理が他のBuilderと比べると複雑。
というものがあるそうです。
僕自身あまりメリットがわかっていないので、コードのご紹介みたいになってしまいました。もっと勉強しないとだめですね。
サンプルコード
GitHubにアップしていますのでご自由にお使いください。
では今回はこの辺で。