デザインパターン(2):Builder


Builderとは

複数のインスタンス間にて共通の処理が必要な場合、その処理を隠蔽することで
同じ処理でも内部処理を異なるものにすることができる実装のこと。 
ここではmainLanguageというフィールドを持つ、Peopleクラスを元に日本人と米国人を作る。

手順①

複数のインスタンス間にて共通の処理を定義するインタフェースを作成する。(=Builderクラス)

Builder.java
public interface Builder {
    void createMainLanguage(); //主言語をセット
    People getResult(); //Peopleインスタンスを返却する
}
People.java
public class People {
    //主語
    private String mainLanguage;

    public String getMainLanguage() {
        return mainLanguage;
    }

    public void setMainLanguage(String mainLanguage) {
        this.mainLanguage = mainLanguage;
    }

    void hello() {
        System.out.println("こんにちは。主言語は" + mainLanguage);
    }
}

手順②

定義したインタフェースの実装を持ったクラスを作成する。(=ConcreteBuilderクラス)
生成するインスタンスの種類が増えるときは、このクラスを生成して増やす

JapaneseBuilder.java
//日本人Builder
public class JapaneseBuilder implements Builder {
    private People people;

    public JapaneseBuilder() {
        this.people = new People();
    }

    @Override
    public void createMainLanguage() {
        people.setMainLanguage("Japanese"); //Japanenseが主言語
    }

    @Override
    public People getResult() {
        return this.people;
    }
}
AmericanBuilder.java
//米国人Builder
public class AmericanBuilder implements Builder {
    private People people;

    public AmericanBuilder() {
        this.people = new People();
    }

    @Override
    public void createMainLanguage() {
        people.setMainLanguage("English"); //Englishが主言語
    }

    @Override
    public People getResult() {
        return this.people;
    }
}

手順③

実際のインスタンス生成を担うクラスを作成する。(=Directorクラス)
※必ずインタフェースをコンストラクタの引数に持たせること
DirectorにBuilderを渡すことにより、ConcreteBuilderクラスに依存しない作りになる。
つまりDirectorは実際のクラスである、ConcreteBuilderが何なのかを意識しない。

Director.java
public class Director {
    private Builder builder;

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

    public People construct() {
        builder.createMainLanguage();
        return builder.getResult();
    }
}

呼び出し方

①Builderインタフェースを型に持つ、builderインスタンスを生成する。
実際の処理は生成時のConcreteBuilderに依存する。
②builderインスタンスを引数として、Directorインスタンスを生成する。

Main.java
public class Main {
    public static void main(String[] args) {
        if (args[0].equals("Japanese")) {
            // 日本人ビルダを生成
            Builder builder = new JapaneseBuilder();
            // DirectorはBulderインタフェースを渡しているだけなので、Builderの内部実装までは知らない。
            Director director = new Director(builder);
            People people = director.construct();
            people.hello();
        } else if (args[0].equals("English")) {
            Builder builder = new AmericanBuilder();
            Director director = new Director(builder);
            People people = director.construct();
            people.hello();
        } else {
            throw new IllegalArgumentException();
        }
    }
}

ちなみにインタフェースではなく、抽象クラスを使用してBuilderパターンを実現してるのもあったけど
どっちがいいんだろ・・・よくわからん。。。