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的子类即可。
缺点:不易增加新的产品。增加新产品的时候需要为每个具体的工厂添加。