デザインパターン入門(Builder)


この記事ではBuilderについてまとめます。
wikipediaによると「オブジェクトの生成過程を抽象化することによって、動的なオブジェクトの生成を可能にする」とあります。
参考:Builder パターン

このパターンはあるクラスにおいて、コンストラクタが複数存在する場合それらをまとめることができるというものです。コンストラクタは名前と引数が一致したものはひとつのみ定義可能で、複数作成する場合は引数の数やデータ型が変わります。数が増えると作るのも面倒、ソースコードの可読性も落ちます。そこでコンストラクタが受け取る引数を外出しします。

 実装例

名前、年齢、身長、体重をパラメータとして保持する人クラスを作る

パターン適用前

public class Human {
    private String name;
    private Integer age;
    private Integer height;
    private Integer weight
    public Human(String name, Integer age, Integer height, Integer weight) {
        this.name = name;
        this.age = age;
        this.height = height;
        this.weight = weight;
    }
    public Human(String name) {
        this.name = name;
    }
    public Human(Integer age) {
        this.age = age;
    }
    public Human(Integer height, Integer weight) {
        this.height = height;
        this.weight = weight;
    }

}
public class Main {
    public static void main(String[] args) {
        Human ha = new Human("kusa");
        Human hb = new Human(1);
        Human hc = new Human(170, 70);
    }
}

パターン適用後

Builder.java
public interface Builder {
    public void name(String name);
    public void age(Integer age);
    public void height(Integer height);
    public void weight(Integer weight);
    public Human getResult();
}
HumanBuilder.java
class HumanBuilder implements Builder {
    private Human human;

    public HumanBuilder() { this.human = new Human(); }

    @Override
    public void name(String name) { human.setName(name); }
    @Override
    public void age(Integer age) { human.setAge(age); }
    @Override
    public void height(Integer height) { human.setHeight(height); }
    @Override
    public void weight(Integer weight) { human.setWeight(weight); }
    @Override
    public Human getResult() { return this.human; }
}
Human.java
public class Human {
    private String name;
    private Integer age;
    private Integer height;
    private Integer weight;

    public void setName(String name) { this.name = name;}
    public void setAge(Integer age) { this.age = age;}
    public void setHeight(Integer height) { this.height = height; }
    public void setWeight(Integer weight) { this.weight = weight; }

    public String getName() { return this.name; }
    public Integer getAge() { return this.age; }
    public Integer getHeight() { return this.height; }
    public Integer getWeight() { return this.weight; }

    public void hello() {
        System.out.printf("name is %s %n",name);
        System.out.printf("age is %d %n", age);
        System.out.printf("height is %d %n", height);
        System.out.printf("weight is %d %n", weight);
    }
}
Director.java
class Director {
    private Builder builder;

    public Director(Builder builder) { this.builder = builder; }

    public void construct() {
        builder.name("kusakari");
        builder.age(30);
        builder.height(175);
        builder.weight(70);
    }
}
Main.java
public class Main {
    public static void main(String[] args) {
        Builder builder = new HumanBuilder();
        Director director = new Director(builder);
        director.construct();
        builder.getResult().hello();
    }
}
結果
$ java Main
name is kusakari 
age is 30 
height is 175 
weight is 70

以上のように、クラス内にコンストラクタが複数あった場合ソースコードの見通しが悪くなり、コード量が多くなります。そのためコンストラクタをDirectorクラス上に出して、Builderインターフェースを実装したHumanBuilderクラスでインスタンスを生成、Main.javaはgetter経由でインスタンスにアクセスします。