デザインパターン(1):AbstractFactory


AbstractFactoryとは

インスタンス生成を専門に行うクラス(Factory)を作成することで、
関連性のあるインスタンスを間違いなく生成するためのデザインパターンのこと。
つまりFactoryクラス毎に生成できるインスタンスが決められている実装のこと。

手順①

関連性のあるクラスをを生成するクラス(=Factoryクラス)を作る。
例):TokyoとJapanese、WashingtonDCとEnglishが関連性がある。

Factory.java
public interface Factory {
    Capital getCapital();
    Language getLanguage();
}
JapanFactory.java
// 日本のFactoryクラス
public class JapanFactory implements Factory {
    @Override
    public Capital getCapital() {
        return new Tokyo(); // 首都は東京
    }

    @Override
    public Language getLanguage() {
        return new Japanese(); // 言語は日本語
    }
}
UsaFactory.java
// アメリカのFactoryクラス
public class UsaFactory implements Factory {
    @Override
    public Capital getCapital() {
        return new WashingtonDC(); //首都はワシントンDC
    }

    @Override
    public Language getLanguage() {
        return new English(); // 言語は英語
    }
}

手順②

Factoryインタフェースで実装されている、メソッドの戻り値である抽象クラスを継承したクラスを作成する。
このクラスが各Factoryクラスで実際に返却されるクラスとなる。
例):Capitalクラスを継承したTokyoクラスや、WashingtonDCクラスが実際にFactoryクラスから返却される。

Capital.java
public abstract class Capital {
    //ここのフィールドは、AbstractFactoryの説明としては特に関係なし。
    protected String name;
    protected int population;
}
Tokyo.java
public class Tokyo extends Capital {
    public Tokyo() {
        this.name = "東京";
        this.population = 13510000;
    }
}
WashingtonDC.java
public class WashingtonDC extends Capital {
    public WashingtonDC() {
        this.name = "ワシントンD.C";
        this.population = 601723;
    }
}

手順③

呼び出し側でFactoryクラスを生成する処理を実装する。このときFactoryクラスを切り替える分岐が必要になる。

Main.java
public class Main {
    public static void main(String[] args) {
        String name = "Japan";
        Factory factory = createFactory(name);
        Capital capital = factory.getCapital();
        Language language = factory.getLanguage();
        System.out.println("首都名は" + capital.name);
        System.out.println("人口は" + capital.population);
    }

    private static Factory createFactory(String name) {
        switch (name) {
            case "Japan":
                return new JapanFactory();
            case "USA":
                return new UsaFactory();
            default:
                throw new IllegalArgumentException();
        }
    }
}
実行結果
首都名は東京
人口は13510000

メリット

Factoryクラス経由でインスタンスを生成することで、関連性を持ったインスタンスを安全に生成することができる。
→JapanFactoryインスタンスを生成することで、必ずTokyoインスタンスとJapaneseインスタンスが生成できる。
(明示的にインスタンスを生成すると誤った組み合わせでインスタンスを生成する恐れがある。)

また抽象クラスで戻り値を取得するため、呼び出し側でFactoryクラスの内部実装を気にする必要がない。
→Tokyoクラスや、WashingtonDCクラスがどういった実装か知る必要がない。