抽象工厂模式

100 阅读2分钟

背景

抽象工厂(Abstract Factory) 的工作是将抽象零件组装成抽象产品

“抽象”是指不考虑具体怎样实现,而是仅关注接口的状态,在abstract factory 模式中将会出现抽象工厂,它会将抽象零件组成为抽象产品。也就是说,我们并不关心零件的具体实现,而是只关心接口(API),我们仅用接口将零件组装成为产品。 体现了依赖倒置原则。

登场角色

AbstractProduct 抽象产品

负责定义AbstractFactory 所需要的零件和产品的 API,如示例代码中的PageLinkTray

AbstractFactory 抽象工厂

负责定义生成零件和产品的API;

Client 委托者

调用 AbstractFactoryAbstractProduct的方法来工作,对于具体的零件,产品和工厂一无所知,如示例代码中的 Main类;

ConcreteProduct 具体产品

负责实现AbstractProduct角色中的接口,如示例代码中的ListLink类,ListTray类,ListPage类;

ConcreteFactory 具体工厂

负责实现AbstractFactory角色中的接口,如示例代码中的ListFactory类;

类图

代码示例

实现将带有层次关系的链接集合制作成HTML文件

抽象类

Factory类

public abstract class Factory {

    public static Factory getFactory(String className) {
        Factory factory = null;
        try {
            factory = (Factory) Class.forName(className).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return factory;
    }


    public abstract Link createLink(String caption, String url);
    public abstract Tray createTray(String caption);
    public abstract Page createPage(String title, String author);
}

Item类,是Link和Tray的父类

public abstract class Item {
    // 标题
    protected String caption;

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

    public abstract String makeHTML();
}

Page类,表示一个页面

/**
 * Page类抽象表示HTML页面的类
 * 如果将Link Tray 看作抽象零件,hbn 则Page就可以看成抽象的产品
 */
public abstract class Page {

    protected String title;

    protected String author;

    protected ArrayList<Item> content = new ArrayList<>();

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

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

    /**
     * 输出内容到页面
     */
    public void output() {
        try {
            String fileName = title + ".html";
            Writer writer = new FileWriter(fileName);
            writer.write(this.makeHTML());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 构造页面的内容
    public abstract String makeHTML();
}

Link类,表示链接

/**
 * 抽象表示HTML链接的类
 */
public abstract class Link extends Item {
    protected String url;

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

Tray类,表示一个列表,列表中的每一个元素都会含有一个列表

/**
 * 表示一个含有多个 link和 tray的容器
 */
public abstract class Tray extends Item {
    protected ArrayList<Item> arrayList = new ArrayList<>();

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

    public void addItem(Item item) {
        arrayList.add(item);
    }
}

具体实现类

ListFactory类

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

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

    @Override
    public Page createPage(String title, String author) {
        return new ListPage(title, author);
    }
}

ListPage类

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

    @Override
    public String makeHTML() {
        StringBuffer stringBuffer = new StringBuffer();

        stringBuffer.append("<html><head><title>" + title + "</title></head>\n");
        stringBuffer.append("<body>\n");
        stringBuffer.append("<h1>" + title +"</h1>\n");
        stringBuffer.append("<ul>\n");
        Iterator<Item> it = content.iterator();

        while (it.hasNext()) {
            Item next = it.next();
            stringBuffer.append(next.makeHTML());
        }

        stringBuffer.append("</ul>\n");
        stringBuffer.append("<hr><address>" + author + "</address>");
        stringBuffer.append("</body></html>\n");

        return stringBuffer.toString();
    }
}

ListLink类

public class ListLink extends Link {

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

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

ListTray类

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

    @Override
    public String makeHTML() {
        StringBuffer stringBuffer = new StringBuffer();

        stringBuffer.append("<li>\n");
        stringBuffer.append(caption + "\n");
        stringBuffer.append("<ul>\n");

        Iterator<Item> it = arrayList.iterator();
        while (it.hasNext()) {
            Item next = it.next();
            stringBuffer.append(next.makeHTML());
        }

        stringBuffer.append("</ul>\n");
        stringBuffer.append("</li>\n");

        return stringBuffer.toString();
    }
}

启动类

public class Main {
    public static void main(String[] args) {
        Factory factory = Factory.getFactory(args[0]);

        Page page = factory.createPage("LinkPage", "杨子轩");
        Tray tray1 = factory.createTray("日报");
        Tray tray2 = factory.createTray("检索引擎");
        Link link1 = factory.createLink("人民日报", "");
        Link link2 = factory.createLink("光明日报", "");
        tray1.addItem(link1);
        tray1.addItem(link2);

        Tray yahoo = factory.createTray("Yahoo");
        Link yahoo_us = factory.createLink("Yahoo!", "");
        Link yahoo_jp = factory.createLink("Yahoo!Japan", "");
        yahoo.addItem(yahoo_jp);
        yahoo.addItem(yahoo_us);
        Link exciteLink = factory.createLink("Excite", "");
        Link google = factory.createLink("Google", "");

        tray2.addItem(yahoo);
        tray2.addItem(exciteLink);
        tray2.addItem(google);

        page.addItem(tray1);
        page.addItem(tray2);

        page.output();
    }
}

功能分析

  1. 容易添加新的工厂,只要重写抽象的零件和工厂即可
  2. 难以添加新的零件,一旦要添加新的零件,就要将其他的具体的工厂进行修改,已经编写完成的具体工厂越多,修改的工作量就会越大