抽象工厂模式 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的子类即可。

缺点:不易增加新的产品。增加新产品的时候需要为每个具体的工厂添加。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值