抽象工廠模式 Abstract Factory Model

package factory;
/**
 * Item類是Link和Tray類的父類。這樣Link類和Tray類就有可替代性
 * caption代表項目的標題
 * makeHTML是一個抽象方法,給子類實現。返回HTML文件的內容**/
public abstract class Item {
	protected String caption;
	public Item(String caption) {
		this.caption=caption;
		
	}
	public abstract String makeHTML();
}
package factory;
/**
 * Link抽象表示HTML的超鏈接類
 * url字段保存超鏈接的地址。**/
public abstract class Link extends Item{
	protected String url;
	public Link(String caption,String url) {
		super(caption);
		this.url=url;
	}
}
package factory;

import java.util.ArrayList;
/**Tray類表示的是含有多個Link類和Tray類的容器(Tray有托盤的意思)
 * Tray用add方法將 Link類和Tray類集合在一起。
 * 爲了表示集合對象是Link類和Tray類我們設置add方法的參數爲Link類和Tray類的父類Item.
 *雖然Link和Tray類也繼承了Item的抽象方法makeHTML但是沒有實現它,所以還是抽象類**/
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);
	}
}
package factory;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.ArrayList;
/**
 * Page類是抽象的表示HTML頁面的類。如果把Link和Tray表示爲抽象的“零件”。那麼Page類就是抽象的產品。
 * title和author分別表示頁面標題和頁面作者的字段。作者名字通過參數傳遞給Page類的構造函數。
 * 可以通過add方法向頁面中增加Item。將會在頁面中顯示出來。
 * output方法首先根據頁面標題確定文件名,接着調用makeHTML方法將自身保存在HTML內容中。
 * 爲了強調用的是Page類自己的makeHTML方法。這裏顯示的加上了this。這裏調用的makeHTML方法十一個抽象方法。
 * output是一個簡單的Template Method模式的方法。**/
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() {
		String filename=title+".html";
		Writer writer;
		try {
			writer = new FileWriter(filename);
			writer.write(this.makeHTML());
			writer.close();
			System.out.println(filename+"編寫完成");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	public abstract String makeHTML();
}
package factory;
/**
 * getFactory可以根據指定的類名生成具體工廠的實例。將參數calssname指定爲具體工廠的類名所對應的字符串。
 * getFactory方法通過調用class的forName方法來動態地讀取類信息,接着使用newInstance方法生成該類的實例,並將其作爲返回值返回給調用者。
 * Class類屬於java.lang包,是用來表示類的類。Class類包含java的標準類庫中的forname是java。langClass中的靜態方法。
 * newInstance是java.lang.Class中的實例方法。
 * getFactory雖然是生成具體工廠,但是返回值的類型是抽象工廠類型。
 * createLink\createTray\createPage等方法是用於在抽象工廠中生成零件和產品的方法。這些方法都是抽象的具體事項交給了Factory類的子類。**/
public abstract class Factory {
	public static Factory getFactory(String classname) {
		Factory factory=null;
		try {
			factory=(Factory)Class.forName(classname).newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			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);
}
package mian;
import factory.*;
/**Main類使用抽象工廠生產零件並將零件組裝成產品。
 * Main類只引入了一個facotry的包,從這一點可以看出,該類並沒有使用任何具體零件、產品、和工廠。
 * 具體工廠的類名是通過命令行來制定的。例如使用listfactory包中的ListFactory類,
 * 就可以在命令行輸入:java Main listfactory.ListFctory
 * Main類會使用getFactory方法色河南工程改參數(arg[0]);對應的工廠,並將其保存在factory變量中。
 * 之後,Main類會使用factory生成Link和Tray,然後將Link和Tray都放到Tray中,最後生成page並將生成結果輸出至文件。
 * **/
public class Main {
	public static void main(String[] args) {
		if(args.length!=1) {
			System.out.println("Usage:java Main class.name.of.ConcreteFactory");
			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("人民日報", "http://www.people.com.cn");
		Link gmw=factory.createLink("光明日報", "http://www.gmw.cn");
		
		Link us_yahoo=factory.createLink("Yahoo!","http://www.yahoo.com/");
		Link jp_yahoo=factory.createLink("Yahoo!Japan", "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("日報");
		traynews.add(people);
		traynews.add(gmw);
		
		Tray trayyahoo=factory.createTray("Yahoo");
		trayyahoo.add(us_yahoo);
		trayyahoo.add(jp_yahoo);
		
		Tray traysearch=factory.createTray("搜索引擎");
		traysearch.add(excite);
		traysearch.add(trayyahoo);
		traysearch.add(google);
		
		Page page=factory.createPage("LinkPage", "Zgh");
		page.add(traynews);
		page.add(traysearch);
		page.output();
	}
}
package listfactory;
import factory.*;
/**
 * ListFactory類實現了Factory類的三個生成方法。方法內部只是分別簡單的new了一個LisLink,ListTray和LinkPage類的實例。
 * (根據實際需要這裏可能需要用Prototype模式來進行clone**/
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);
	}
	
}
package listfactory;

import factory.Link;
/**
 * ListLink類是Link類的子類。
 * 實現Link類中的makeHTML抽象方法。ListLink類使用<li>標籤和<a>標籤來製作HTML片段。
 * 這樣HTML片段也可以與ListTray和ListPage的結果並合起來,就如同螺栓和螺母擰在一起。
 * **/
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是Tray類的子類。
 * makeHTML方法的實現:tray中保存了所需要以HTML形式輸出的Item,而負責將它們以HTMLX格式輸出的就是makeItem方法了。
 * 這裏並不關心變量item中保存的實例究竟是ListLink還是ListTray。只是簡單的調用了它們的makeHTML語句。
 * **/
package listfactory;

import java.util.Iterator;

import factory.Item;
import factory.Tray;

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 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();
		
	}

}
/**
 * **/
package listfactory;
import java.util.Iterator;
import factory.Item;
import factory.Page;

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

}
package tablefactory;
import factory.*;
public class TableFactory extends Factory{

	@Override
	public Link createLink(String caption, String url) {
		return new TableLink(caption,url);
	}

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

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

}
/**
 * tableLink的makeHTML方法的處理是使用<td>標籤來創建表格的列**/
package tablefactory;
import factory.Link;

public class TableLink extends Link {

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

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

}
/**其makeHTML方法的處理是使用<td>和<table>標籤輸出Item**/
package tablefactory;
import java.util.Iterator;

import factory.Item;
import factory.Tray;

public class TableTray extends Tray {

	public TableTray(String caption) {
		super(caption);
		// TODO Auto-generated constructor stub
	}

	@Override
	public String makeHTML() {
		StringBuffer buffer=new StringBuffer();
		buffer.append("<td>");
		buffer.append("<table width=\"100%\" border=\"1\"><tr>");
		buffer.append("<td bgcolor=\"#cccccc\" align=\"center\" "
				+ "colspan=\""+tray.size()+"\"><b>"+caption+"</b></td>");
		buffer.append("</tr>\n");
		buffer.append("<tr>\n");
		Iterator it=tray.iterator();
		while(it.hasNext()) {
			Item item=(Item) it.next();
			buffer.append(item.makeHTML());
		}
		buffer.append("</tr></table>");
		buffer.append("</td>");
		return buffer.toString();
	}

}
/****/
package tablefactory;

import java.util.Iterator;

import factory.*;
public class TablePage extends Page {

	public TablePage(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("<table width=\"80%\" border=\"3\">\n");
		Iterator it=content.iterator();
		while(it.hasNext()) {
			Item item=(Item) it.next();
			buffer.append(item.makeHTML());
		}
		buffer.append("</table>\n");
		buffer.append("<hr><address>"+author+"</address>");
		buffer.append("</body></html>\n");
		return buffer.toString();
	}

}

以上是每個類放置的包的位置。有兩個工廠的實例,listfactory和tablefactory.

在命令行運行時,輸入參數需要用全包名。比如輸入TableFactory是找不到類的。需要輸入tablefactory.TableFactory才行。運行出來在本地寫了一個html文件。用瀏覽器打開即可。

Abstract Factory角色

AbstractProduct(抽象產品)

AbstractProduct角色負責定義AbstractFactory角色所生成的抽象零件和產品的接口(API)。在示例程序中Link、Tray和Page類扮演此角色。

AbstratcFactory(抽象工廠)

該角色負責定義用於生成抽象產品的接口。在示例程序中Factory扮演此角色。

Client(委託者)

Client角色會調用AbstractFactory和AbstractProduct角色的接口來進行工作,對於零件、產品和工廠一無所知。在示例程序中main扮演此角色。

ConcreteProduct(具體產品)

ConcreteProduct角色負責實現AbstractProduct角色的接口。ListLin/ListTray/ListPage等扮演此角色。

ConcreteFactory(具體工廠)

負責實現AbstractFactory角色的接口。在示例程序中紅由ListFactory和TableFactory扮演此角色。‘

抽象工廠的優缺點:

優點:易於增加新的工廠。增加新的工廠時只需要添加Factory ,Link,Tray,和Page的子類即可。

缺點:不易增加新的產品。增加新產品的時候需要爲每個具體的工廠添加。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章