一天一個設計模式——Abstract Factory抽象工廠模式

1、模式說明html

  前面學習了工廠方法(Factory Method)模式。在工廠方法模式中,在工廠方法模式中,父類決定如何生成實例,但並不決定所要生成的具體類,具體的處理交由子類來處理。這裏學習的抽象工廠方法模式中,抽象工廠使用抽象的零件組裝成抽象的產品。即便用包含特定的方法接口零件,將零件組裝成抽象產品。java

2、模式類圖:設計模式

  上面的類圖中包含兩個包:包含抽象工廠,抽象零件,抽象產品的類所在的包以及具體工廠實現類的包。app

3、代碼示例ide

一、Item類:學習

package com.designpattern.cn.abstractfactorypattern.abstractfactory;

//抽象的零件Item
public abstract class Item {
    protected String caption;
    public Item(String caption){
        this.caption = caption;
    }
    public abstract String makeHtml();
}
View Code

Item類是下面兩個產品的父類,其中的MakeHtml是抽象方法,須要在子類中實現。ui

二、Link類:this

package com.designpattern.cn.abstractfactorypattern.abstractfactory;

//抽象的零件Link
public abstract class Link extends Item {
    protected String url;
    public Link(String caption, String url){
        super(caption);
        this.url = url;
    }
}
View Code

Link類被定義爲抽象類,初看彷佛並不包含抽象方法,可是,Link類繼承了抽象類Item,且沒有實現MakeHtml抽象方法,則Link類仍是一個抽象類。google

三、Tray類:url

package com.designpattern.cn.abstractfactorypattern.abstractfactory;

import java.util.ArrayList;

//抽象的Tray類
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);
    }
}
View Code

一樣的Tray類也是抽象類。

四、抽象的產品Product類:

package com.designpattern.cn.abstractfactorypattern.abstractfactory;

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

public abstract class Page {
    protected String title;
    protected String author;
    protected ArrayList content = new ArrayList();
    public Page(String title, String author){
        this.title = title;
        this.author = author;
    }
    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();
}
View Code

五、抽象工廠Factory類:

package com.designpattern.cn.abstractfactorypattern.abstractfactory;

public abstract class Factory {
    public static Factory getFactory(String classname){
        Factory factory = null;
        try {
            factory = (Factory)Class.forName(classname).newInstance();
        }catch (ClassNotFoundException | InstantiationException | IllegalAccessException 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);
}
View Code

該類中使用getFactory方法來根據類名聲稱具體的工廠示例,該方法經過調用Class類的forName方法動態的讀取類信息,接着使用newInstance方法生成類的實例,並將其做爲返回值給調用者。

  須要注意的是,雖然getFactory方法生成的是具體工廠的實例,但因爲返回值的類型是抽象工廠類型。createLink、createTray、createPage方法是用於在抽象工廠中生成抽象零件和產品的抽象方法,具體的實現交由子類,不過在這裏肯定了方法的名字和簽名。

 

  看完了模式的抽象類,接下來看具體的實現類:

一、具體的工廠ListFactory類:

package com.designpattern.cn.abstractfactorypattern.listfactory;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Factory;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Link;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Page;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Tray;

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

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

    public Page createPage(String title, String author){
        return new ListPage(title, author);
    }
}
View Code

二、具體的零件ListLink類:

package com.designpattern.cn.abstractfactorypattern.listfactory;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Link;

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";
    }
}
View Code

三、具體的零件ListTray類:

package com.designpattern.cn.abstractfactorypattern.listfactory;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Item;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Tray;

import java.util.Iterator;

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

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

四、具體的零件LIstPage類:

package com.designpattern.cn.abstractfactorypattern.listfactory;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Item;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Page;

import java.util.Iterator;


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

    @Override
    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 iterator = content.iterator();
        while(iterator.hasNext()){
            Item item = (Item)iterator.next();
            buffer.append(item.makeHtml());
        }
        buffer.append("</ul>\n");
        buffer.append("<hr><address>" + author + "</address>");
        buffer.append("</body></html>\n");
        return buffer.toString();
    }
}
View Code

五、運行結果:

Main類代碼:

package com.designpattern.cn.abstractfactorypattern;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Factory;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Link;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Page;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Tray;
import com.designpattern.cn.abstractfactorypattern.listfactory.ListFactory;

public class Main {
    public static void main(String[] args){
        System.out.println(ListFactory.class.getName());
        if(args.length!= 1){
            System.out.println("Usage: java Main class.name.of.ConcreateFactory");
            System.out.println("Example 1: java Main listFactory.ListFactory");
            System.out.println("Example 2: java Main tablefactory.TableFactory");
            System.exit(0);
        }
        Factory factory = Factory.getFactory(args[0]);

        Link people = factory.createLink("People's Daily", "http://www.people.com.cn/");
        Link gmw = factory.createLink("gmw", "http://www.gmw.cn/");
        Link us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");
        Link jp_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.co.jp/");
        Link excite = factory.createLink("Excite", "http://www.excite.com");
        Link google = factory.createLink("Google", "http://www.google.com/");

        Tray traynews = factory.createTray(" Daily ");
        traynews.add(people);
        traynews.add(gmw);

        Tray trayyahoo = factory.createTray("Yahoo!");
        trayyahoo.add(us_yahoo);
        trayyahoo.add(jp_yahoo);

        Tray traysearch = factory.createTray("Search engeen");
        traysearch.add(trayyahoo);
        traysearch.add(excite);
        traysearch.add(google);

        Page page = factory.createPage("LinkPage", "Rumble");
        page.add(traynews);
        page.add(traysearch);
        page.output();
    }
}
View Code

 

4、模式中的角色

  • AbstractProduct抽象產品角色:AbstractProduct負責定義AbstractFactory抽象工廠角色所生成的零件和產品接口。(程序示例中的LInk、Tray、Page類)
  • AbstractFactory抽象工廠角色:負責定義用於生成抽象產品的接口。
  • Client委託者角色:Client調用AbstractFactory和Abstract Product角色的接口來進行工做。程序中由Main扮演該角色。

5、抽象工廠模式的特色

  • 易於增長具體的工廠:很清楚實現一個具體的工廠應該實現哪些方法,對於示例,當須要增長新的工廠時,須要作的就是編寫Factory、Link、Tray、Page這幾個類的子類。任什麼時候候都不須要修改抽象類和Main類。
  • 難以增長新零件:若是要在一個抽象工廠中增長零件,這時候除了修改抽象工廠,還要修改全部的實例工廠。

6、相關的設計模式

  • Builder模式:分階段的製做複雜實例
  • Factory Method模式:在抽象工廠Abstract Factory模式中,生成零件和產品可能會使用到工廠方法模式
  • Composite模式
  • Singleton模式

最後,抽象工廠模式在Spring中也是有用到的,因此須要好好消化一下。

相關文章
相關標籤/搜索