AndroidでBuilder patternを実装したので改めて自分なりにまとめてみることにする。
参考書籍
EFFECTIVE JAVA 第2版 (The Java Series)
help somebody understand
・Builderとは、建築者を意味している。
・ビルを建てる時は、地盤を固め、骨組みをつくり、下から上に順番ずつ作っていく。
・コンストラクタなどに多くの引数を渡さなければならない場合(hint 4つ以上 or 増えていきそうな場合)、Builderパターンを考える。
わかりづらくなるパターンの例
「Telescoping Constractor」pattern
*テレスコーピング(伸縮)コンストラクラタ
public class Member {
private String mName;
private int mAge;
private String mJob;
private String mHobby;
private boolean mMarriedFlg;
public Member(String name, int age) {
this(name, age, null, null);
}
public Member(String name, int age, String job) {
this(name, age, job, null, false);
}
public Member(String name, int age, String job, String hobby) {
this(name, age, job, hobby, false);
}
public Member(String name, int age, String job, String hobby, boolean marriedFlg) {
this.mName = name;
this.mAge = age;
this.mJob = job;
this.mHobby = hobby;
this.mMarriedFlg = marriedFlg;
}
}
4つのパラメータなので、まだクライアント側(このクラスを使用する側)も書くのが困難ではないと思うが、さらに増えていくと、
コードを書く、読む、という行為が困難になり、次第に保守性が失われていく。
そして、パラメータが多い(又は多くなる)ことによる、先ほどの欠点を補うのがJavaBeanパターンになる。
可読性が良くなります。
しかし、この場合、また別の問題が起こる。
必須パラメータとしたいパラメータ(name, age)を、セットし忘れる可能性があり、システムが不整合な状態になる可能性があり得る。
public class Member {
private String mName;
private int mAge;
private String mJob;
private String mHobby;
private boolean mMarriedFlg;
public String getName() {
return mName;
}
public void setName(String name) {
this.mName = name;
}
public int getAge() {
return mAge;
}
public void setAge(int age) {
this.mAge = age;
}
public String getJob() {
return mJob;
}
public void setJob(String job) {
this.mJob = job;
}
public String getHobby() {
return mHobby;
}
public void setHobby(String hobby) {
this.mHobby = hobby;
}
public boolean isMarriedFlg() {
return mMarriedFlg;
}
public void setMarriedFlg(boolean marriedFlg) {
this.mMarriedFlg = marriedFlg;
}
}
上記2つの欠点は、コードの保守性が悪くなり、整合性が取れなくなる。
そこで、テレスコーピング(伸縮)コンストラクラタとJavaBeanの欠点を補うのが、Builderパターンになる。
public class Member {
// require parameter
private final String mName;
private final int mAge;
// option parameter
private final String mJob;
private final String mHobby;
private final boolean mMarriedFlg;
public static class Builder {
// require parameter
private String mName;
private int mAge;
// option parameter
private String mJob;
private String mHobby;
private boolean mMarriedFlg = false;
public Builder(String name, int age) {
this.mName = name;
this.mAge = age;
}
public Builder setJob(String job) {
this.mJob = job;
return this;
}
public Builder setHobby(String hobby) {
this.mHobby = hobby;
return this;
}
public Builder setMarried(boolean flg) {
this.mMarriedFlg = flg;
return this;
}
public Member build() {
return new Member(this);
}
}
// point! DesignPattern.Builder.BuilderPattern.TelescopingConstractor.Member class constractor must be private.
private Member(Builder builder) {
this.mName = builder.mName;
this.mAge = builder.mAge;
this.mJob = builder.mJob;
this.mHobby = builder.mHobby;
this.mMarriedFlg = builder.mMarriedFlg;
}
// getter 省略
}
Builder pattern design help
・Builder pattern classのinstanceを作成し、Builderのconstractorに、required parameterを入れる。
・Member classのconstractorは、privateにして、隠蔽する。