目录
一、什么是抽象工厂模式
为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类,这称之为抽象工厂模式(Abstract Factory)。我们并不关心零件的具体实现,而是只关心接口(API)。我们仅使用该接口(API)将零件组装称为产品。
二、示例程序
1、抽象的零件:Item类
package com.as.module.abstractfactory;
/**
* 抽象的零件
* @author Andy
* @date 2021/4/29 23:16
*/
public abstract class Item {
protected String caption;
public Item(String caption) {
this.caption = caption;
}
public abstract String makeHTML();
}
2、抽象的零件:Link类
package com.as.module.abstractfactory;
/**
* TODO
*
* @author Andy
* @date 2021/4/29 23:18
*/
public abstract class Link extends Item {
protected String url;
public Link(String caption,String url) {
super(caption);
this.url = url;
}
}
3、抽象的零件:Tray类
package com.as.module.abstractfactory;
import java.util.ArrayList;
/**
* TODO
*
* @author Andy
* @date 2021/4/29 23:20
*/
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);
}
}
4、抽象的产品:Page类
package com.as.module.abstractfactory;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
/**
* 抽象的产品
* @author Andy
* @date 2021/4/29 23:22
*/
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";
try {
Writer writer = new FileWriter(filename);
writer.write(this.makeHTML());
writer.close();
System.out.println(filename+"编写完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public abstract String makeHTML();
}
5、抽象的工厂:Factory类
package com.as.module.abstractfactory;
/**
* 抽象的工厂
* @author Andy
* @date 2021/4/29 23:31
*/
public abstract class Factory {
public static Factory getFactory(String className){
Factory factory = null;
try {
factory = (Factory)Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception 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);
}
6、具体的工厂:ListFactory类
package com.as.module.abstractfactory;
/**
* 具体的工厂
* @author Andy
* @date 2021/4/29 23:36
*/
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);
}
}
7、具体的零件:ListLink类
package com.as.module.abstractfactory;
/**
* 具体的零件
* @author Andy
* @date 2021/4/29 23:37
*/
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";
}
}
8、具体的零件:ListTray类
package com.as.module.abstractfactory;
import java.util.Iterator;
/**
* TODO
*
* @author Andy
* @date 2021/4/29 23:43
*/
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();
}
}
9、具体的零件:ListPage类
package com.as.module.abstractfactory;
import java.util.Iterator;
/**
* 具体的产品
* @author Andy
* @date 2021/5/4 10:42
*/
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();
}
}
10、抽象工厂方法测试用例
package com.as.module.abstractfactory;
import java.util.List;
/**
*
* @author Andy
* @date 2021/5/4 10:54
*/
public class TestAbstractFactory {
public static void main(String[] args) {
Factory factory = Factory.getFactory("com.as.module.abstractfactory.ListFactory");
Link people = factory.createLink("人民日报","http://www.people.com.cn/");
Link gmw = factory.createLink("光明日报","http://www.gmw.cn/");
Link baidu = factory.createLink("Baidu","http://www.baidu.com/");
Link google = factory.createLink("Google","http://www.google.com/");
Tray traynews = factory.createTray("日报");
traynews.add(people);
traynews.add(gmw);
Tray traysearch = factory.createTray("搜索引擎");
traysearch.add(baidu);
traysearch.add(google);
Page page = factory.createPage("LinkPage","Andy");
page.add(traynews);
page.add(traysearch);
page.output();
}
}
运行结果:
三、UML
登场角色:
1、AbstractProduct(抽象产品)
AbstractProduct角色负责定义AbstractPFactory角色所生成的抽象零件和产品的接口。在示例程序中,由Link类,Tray类和Page类扮演此角色
2、AbstractFactory(抽象工厂)
AbstractFactory角色负责定义用于生成抽象产品的接口。在示例程序中,由Factory
3、Client(委托者)
Client角色仅会调用AbstractProduct角色和AbstractFactory角色来进行工作,对于具体的零件,产品,工厂一无所知。示例程序中,由具体的TestAbstractFactory 扮演此角色
4、ConcreteProduct(具体产品)
ConcreteProduct角色负责实现抽象产品角色的接口,示例程序中,由ListLink,ListTray,ListPage类扮演此角色
5、ConcreteFactory(具体工厂)
ConcreteFactory角色负责实现AbstractFactory的接口,示例程序中ListFactory扮演此角色
四、拓展思路与注意事项
1、易于增加具体的工厂
在AbstractFactory模式中增加具体的工厂是非常容易的。这里说的“容易"是指需要编写哪些类和需要实现哪些方法都非常清楚。
假设我们现在要在示例程序中增加新的具体工厂,那么需要做的就是编写Factory、Tray、Link、Page的子类,并实现他们定义的抽象方法,也就是将factory包中的抽象部分全部具体化即可。
这样一来,无论要增加多少个具体工厂,都无需修改抽象工厂和Main部分
2、难以增加新的零件
试想一下要在AbstractFactory模式增加新的零件时应当如何做。例如,我们要在factory包中增加一个表示图像的Picture零件。这时,我们必须要对所有的具体工厂进行相应的修改才行。例如,在listFactory包中,我们必须要做以下修改
(1)在ListFactory包中加入createPicture方法
(2)新增listPicture类
已经完成的具体的工厂越多,修改的工作量越大