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にして、隠蔽する。