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的子類即可。
缺點:不易增加新的產品。增加新產品的時候需要爲每個具體的工廠添加。