こんにちは!ぐちです。
久しぶりのデザインパターンの続編です。笑
イマイチこのデザインパターンのメリットがわかっていなくて、避けてたわけではないんですが、遠退いてしまっていました。
コードだけの列挙になるような気もしていますが、とりあえず今回は下記の記事七つ目をご紹介したいと思います。
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にアップしていますのでご自由にお使いください。
では今回はこの辺で。