Builderパターン

AndroidでBuilder patternを実装したので改めて自分なりにまとめてみることにする。

参考書籍
EFFECTIVE JAVA 第2版 (The Java Series)

増補改訂版 Java言語で学ぶデザインパターン入門

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

ABOUTこの記事をかいた人

hundredappsの管理人であり、ソフトウェア開発者です。 開発したソフトウェアで、世の中の不便を1つでも改善できたらと思います。