デザインパターン学習メモ:「Abstract Factory」


このパターンの目的

GoF本によると、「互いに関連したり依存し合うオブジェクト群を、その具象クラスを明確にせずに生成するためのインタフェースを提供する」となっている。

「オブジェクト群」というのがポイントで、このあとの例で言うと、「Markdownを生成するためのオブジェクト群」、「HTMLを生成するためのオブジェクト群」のように環境や設定によってオブジェクトを切り替えたい時に、このパターンは有効である。

オブジェクト群の実体化方法に関する規則はFactoryクラス内に隠蔽され、使用と生成を切り離すことが可能になる。

実装例

Main.java
// 実行するためのクラス
public class Main {
    public static void main(String[] args) {
        Client client = new Client(new MarkdownFactory());
        client.outputText("Headline 1", "important text.");
    }
}
Client.java
// factoryフィールドによって動作を切り替える
public class Client {
    public AbstractFactory factory;

    public Client(AbstractFactory factory) {
        this.factory = factory;
    }

    public String createText(String headlineText, String importantText) {
        Headline headline = factory.getHeadline();  // 注目
        StrongText strongText = factory.getStrongText();  // 注目

        System.out.println(headline.createHeadline(headlineText));
        System.out.println(strongText.createStrongText(importantText));
    }
}
AbstractFactory.java
abstract public class AbstractFactory {
    abstract Headline getHeadline();
    abstract StrongText getStrongText();
}
MarkdownFactory.java
public class MarkdownFactory extends AbstractFactory {

    @Override
    Headline getHeadline() {
        return new MarkdownHeadline();
    }

    @Override
    StrongText getStrongText() {
        return new MarkdownStrongText();
    }
}
HtmlFactory.java
public class HtmlFactory extends AbstractFactory {

    @Override
    public Headline getHeadline() {
        return new HtmlHeadline();
    }

    @Override
    public StrongText getStrongText() {
        return new HtmlStrongText();
    }
}
MarkdownHeadline.java
public class MarkdownHeadline implements Headline {

    @Override
    public String createHeadline(String string) {
        return "#" + string;
    }
}
MarkdownStrongText.java
public class MarkdownStrongText implements StrongText {

    @Override
    public String createStrongText(String text) {
        return "**" + text +  "**";
    }
}

HtmlHeadline.javaMarkdownStrongText.javaのコードは割愛する

実行例

Mainクラスを実行した結果

#Headline 1
**important text.**

Abstract Factoryパターンを使わないとどうなる?

Clientの外からHeadlineStrongTextを渡すなら、下記のようなコードになる。
各環境用のオブジェクト(Markdown用ならMarkdown用)を不整合なく保持するよう強制できていない。

Client.java
public class Client {
    private Headline headline;
    private StrongText StrongText;

    public Client(Headline headline, StrongText strongText) {
        this.headline = headline;
        this.strongText = strongText;
    }

    public void outputText(String headlineText, String importantText) {
        System.out.println(headline.createHeadline(headlineText));
        System.out.println(strongText.createStrongText(importantText));
    }
}

そして、オブジェクト群の生成が使用者側に移り、使用する具象クラスと生成規則を知らなければいけなくなった。

Main.java
// 実行するためのクラス
public class Main {
    public static void main(String[] args) {
        Headline headline = new MarkdownHeadline();
        StrongText strongText = new MarkdownStrongText();

        Client client = new Client(headline, strongText);
        client.outputText("Headline 1", "important text.");
    }
}

Abstract Factoryパターンによって隠蔽されていた部分が、外部へ漏れてしまった。

参考文献

  • エリック ガンマ、ラルフ ジョンソン、リチャード ヘルム、ジョン プリシディース(1999)『オブジェクト指向における再利用のためのデザインパターン 改訂版』本位田 真一 / 吉田 和樹 監訳、ソフトバンククリエイティブ
  • アラン・シャロウェイ、ジェームズ・R・トロット(2014)『デザインパターンととともに学ぶ オブジェクト指向のこころ』村上雅章訳、丸善出版