Design Pattern | Abstract Factory Methods

Abstract Factoryパターンとは?

  • Abstract Factoryは抽象工場という意味である。
  • 抽象的であるとは、具体的にどのように実装されているかは考慮せず、インターフェースだけに注目している状態である。
  • Abstract Factoryパターンは、部品の具体的な実装に注目せず、インターフェースに注目する。そして、そのインターフェースだけを使って部品を組み立て、製品としてまとめる方式である。
  • 関連部品を組み合わせて製品を作るものである。
  • GoFデザインパターンでは、生成に関するデザインパターンに分類される。

Abstract Factoryパターンのサンプルプログラム

お気に入り一覧をHTML形式で出力するサンプルプログラムである。

Class Diagram
Abstract Factory Pattern Class Diagram

1. Factoryクラス

抽象工場を代表するクラスである。Link、Tray、Pageを作る。

Factory.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

public abstract class Factory {

    public abstract Link createLink(String caption, String url);

    public abstract Tray createTray(String caption);

    public abstract Page createPage(String title);

    public static Factory getFactory(String classname) {
        Factory factory = null;
        try {
            factory = (Factory) Class.forName(classname).getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            System.err.println("클래스 " + classname + "를 찾을 수 없습니다.");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factory;
    }
}

2. Itemクラス

LinkとTrayを統一的に扱うクラスである。

Item.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

public abstract class Item {
    protected String caption;

    public Item(String caption) {
        this.caption = caption;
    }

    public abstract String makeHTML();
}

3. Linkクラス

抽象部品: HTMLリンクを表すクラスである。

Link.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

public abstract class Link extends Item {
    protected String url;

    public Link(String caption, String url) {
        super(caption);
        this.url = url;
    }
}

4. Trayクラス

抽象部品: LinkとTrayを集めたクラスである。

Tray.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

import java.util.ArrayList;

public abstract class Tray extends Item {
    protected ArrayList tray = new ArrayList();

    public Tray(String caption) {
        super(caption);
    }

    public void add(Item item) {
        tray.add(item);
    }
}

5. Pageクラス

抽象部品: HTMLページを表すクラスである。

Page.java

package com.devkuma.designpattern.creational.abstractfactory.factory;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;

public abstract class Page {
    protected String title;
    protected ArrayList content = new ArrayList();

    public Page(String title) {
        this.title = title;
    }

    public void add(Item item) {
        content.add(item);
    }

    public void output() {
        try {
            String filename = title + ".html";
            Writer writer = new FileWriter(filename);
            writer.write(this.makeHTML());
            writer.close();
            System.out.println(filename + "을 생성했습니다.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public abstract String makeHTML();
}

6. ListFactoryクラス

具体的な工場を表すクラスである。ListLink、ListTray、ListPageを作る。

ListFactory.java

package com.devkuma.designpattern.creational.abstractfactory.listfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Factory;
import com.devkuma.designpattern.creational.abstractfactory.factory.Link;
import com.devkuma.designpattern.creational.abstractfactory.factory.Page;
import com.devkuma.designpattern.creational.abstractfactory.factory.Tray;

public class ListFactory extends Factory {
    public Link createLink(String caption, String url) {
        return new ListLink(caption, url);
    }

    public Tray createTray(String caption) {
        return new ListTray(caption);
    }

    public Page createPage(String title) {
        return new ListPage(title);
    }
}

7. ListLinkクラス

具体的な部品: HTMLリンクを表すクラスである。

ListLink.java

package com.devkuma.designpattern.creational.abstractfactory.listfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Link;

public class ListLink extends Link {
    public ListLink(String caption, String url) {
        super(caption, url);
    }

    public String makeHTML() {
        return "  <li><a href=\"" + url + "\">" + caption + "</a></li>\n";
    }
}

8. ListTrayクラス

具体的な部品: LinkやTrayを集めたクラスである。

ListTray.java

package com.devkuma.designpattern.creational.abstractfactory.listfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Item;
import com.devkuma.designpattern.creational.abstractfactory.factory.Tray;

import java.util.Iterator;

public class ListTray extends Tray {
    public ListTray(String caption) {
        super(caption);
    }

    public String makeHTML() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<li>\n");
        buffer.append(caption + "\n");
        buffer.append("<ul>\n");
        Iterator it = tray.iterator();
        while (it.hasNext()) {
            Item item = (Item) it.next();
            buffer.append(item.makeHTML());
        }
        buffer.append("</ul>\n");
        buffer.append("</li>\n");
        return buffer.toString();
    }
}

9. ListPageクラス

具体的な部品: HTMLページを表すクラスである。

ListPage.java

package com.devkuma.designpattern.creational.abstractfactory.listfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Item;
import com.devkuma.designpattern.creational.abstractfactory.factory.Page;

import java.util.Iterator;

public class ListPage extends Page {
    public ListPage(String title) {
        super(title);
    }

    public String makeHTML() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<html><head><title>" + title + "</title></head>\n");
        buffer.append("<body>\n");
        buffer.append("<h1>" + title + "</h1>\n");
        buffer.append("<ul>\n");
        Iterator it = content.iterator();
        while (it.hasNext()) {
            Item item = (Item) it.next();
            buffer.append(item.makeHTML());
        }
        buffer.append("</ul>\n");
        buffer.append("</body></html>\n");
        return buffer.toString();
    }
}

10. Mainクラス

メイン処理を実行するクラスである。

Main.java

package com.devkuma.designpattern.creational.abstractfactory;

import com.devkuma.designpattern.creational.abstractfactory.factory.Factory;
import com.devkuma.designpattern.creational.abstractfactory.factory.Link;
import com.devkuma.designpattern.creational.abstractfactory.factory.Page;
import com.devkuma.designpattern.creational.abstractfactory.factory.Tray;

public class Main {
    public static void main(String[] args) {

        Factory factory = Factory.getFactory("com.devkuma.designpattern.creational.abstractfactory.listfactory.ListFactory");

        Link devkuma = factory.createLink("Devkuma", "https://www.devkuma.com//");
        Link araikuma = factory.createLink("araikuma", "https://araikuma.tistory.com/");

        Link naver = factory.createLink("Naver", "https://www.naver.com/");
        Link daum = factory.createLink("Daum", "https://www.daum.com/");
        Link google = factory.createLink("Google", "https://www.google.com/");

        Tray pgTray = factory.createTray("프로그래밍");
        pgTray.add(devkuma);
        pgTray.add(araikuma);

        Tray searchTray = factory.createTray("검색사이트");
        searchTray.add(naver);
        searchTray.add(daum);
        searchTray.add(google);

        Page page = factory.createPage("즐겨찾기");
        page.add(pgTray);
        page.add(searchTray);
        page.output();
    }
}

11. 実行結果

プログラムで生成したファイルは以下のとおりである。

즐겨찾기.html

<html><head><title>즐겨찾기</title></head>
<body>
<h1>즐겨찾기</h1>
<ul>
<li>
프로그래밍
<ul>
  <li><a href="https://www.devkuma.com//">Devkuma</a></li>
  <li><a href="https://araikuma.tistory.com/">araikuma</a></li>
</ul>
</li>
<li>
검색사이트
<ul>
  <li><a href="https://www.naver.com/">Naver</a></li>
  <li><a href="https://www.daum.com/">Daum</a></li>
  <li><a href="https://www.google.com/">Google</a></li>
</ul>
</li>
</ul>
</body></html>

Abstract Factoryパターンのメリット

例えば、サンプルプログラムに新しい具体的な工場を追加する場合、Factory、Link、Tray、Pageのサブクラスを作り、それぞれの抽象メソッドを実装することになる。
つまり、factoryパッケージのクラスが持っている抽象部分を具体化していくだけである。このとき、どれだけ具体的な工場を追加しても、抽象工場を修正する必要はない。