抽象工厂模式(将关联零件组成产品)
用处
将“抽象零件”组装为“抽象产品”(创建复杂对象)
角色
- AbstractProduct(抽象产品)
该角色负责定义AbstractFactory角色所生成的抽象零件和产品的方法(API)。 - AbstracFactory(抽象工厂)
该角色负责定义用于生成抽象产品的方法(API)。 - Client(委托者)
该角色仅会调用AbstractFactory角色和AbstractProduct角色的方法(API)来进行工作,对具体的零件、产品、工厂一无所知。 - ConcreteProduct(具体产品)
该角色负责实现AbstractProduct角色负责的方法(API) - ConcreteFactory(具体工厂)
该角色负责实现AbstractFactory角色的方法(API)
类图
类图比较复杂,总结以下几点
- 分为抽象工厂和具体工厂两个模块
- 抽象工厂模块中,定义了一个抽象工厂类,在其中定义了创建产品的抽象方法,每个抽象产品有自己的抽象方法。
- 在具体工厂模块中,定义了一个具体工厂类,继承抽象工厂类并重写了方法,用于获取具体产品,每个具体产品都继承了对应抽象类并重写了抽象方法
举例
package 设计模式.创建型模式.工厂模式.抽象工厂模式;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
Factory factory = Factory.getFactory("设计模式.创建型模式.工厂模式.抽象工厂模式.ListFactory");
Link people = factory.createLink("人民日报","http://www.people.com.cn/");
Link gmw = factory.createLink("光明日报","http://www.gmw.cn/");
Tray traynews = factory.createTray("日报");
traynews.add(people);
traynews.add(gmw);
Page page = factory.createPage("LinkPage","杨文轩");
page.add(traynews);
page.output();
}
}
abstract class Item{
protected String caption;
public Item(String caption){
this.caption = caption;
}
public abstract String makeHTML();
}
//AbstractProduct角色
abstract class Link extends Item{
protected String url;
public Link(String caption,String url){
super(caption);
this.url = url;
}
public abstract String makeHTML();
}
//AbstractProduct角色
abstract class Tray extends Item{
protected ArrayList tray = new ArrayList();
protected String caption;
public Tray(String caption){
super(caption);
}
public void add(Item item){
tray.add(item);
}
}
//AbstractProduct角色
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(){
try{
String filename = title +".html";
Writer writer = new FileWriter(filename);
writer.write(this.makeHTML()); //模板方法模式应用
writer.close();
System.out.println(filename+"编写完成");
}catch(IOException e){
e.printStackTrace();
}
}
public abstract String makeHTML();
}
//AbstractFactory角色
abstract class Factory{
public static Factory getFactory(String classname){
Factory factory = null;
try{
factory = (Factory)Class.forName(classname).newInstance();
}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);
}
//ConcreteFactory角色
class ListFactory extends Factory{
public Link createLink(String caption,String url){
return new ListLink(caption,url);
}
public Tray createTray(String caption){
return new ListTray(caption);
}
public Page createPage(String title,String author){
return new ListPage(title,author);
}
}
//ConcreteProduct角色
class ListLink extends Link{
public ListLink(String caption,String url){
super(caption,url);
}
public String makeHTML(){
return "<li><a href=\""+url+"\">"+caption+"</a></li>\n";
}
}
//ConcreteProduct角色
class ListTray extends Tray{
public ListTray(String caption){
super(caption);
}
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();
}
}
//ConcreteProduct角色
class ListPage extends Page{
public ListPage(String title,String author){
super(title,author);
}
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();
}
}
如果想要新增生产其他产品的工厂,只需要写一个新的具体工厂,及其所要生产的具体产品类即可。本例中是一个新的具体工厂和继承Link,Tray,Page的子类。
总结
- 用于创建复杂对象
- 抽象工厂模式易于增加工厂(只需要增加类,不需要改写好的代码,符合开闭原则),而难以增加新的产品(违反开闭原则)。
基于上述特性,引入一个产品簇与产品线的概念
- 产品簇指具有相同或相似的功能结构或性能,共享主要的产品特征、组件或子结构,并通过变型配置来满足特定市场的一组产品的聚类,举例:苹果手机,华为手机,小米手机,属于同一产品簇
- 产品线是指一群相关的产品,举例:苹果手机,苹果电脑,苹果平板,属于同一产品线
我们可以看出,假设把每个具体工厂都视作一个品牌,那么可以发现由于易于增加工厂的特性,抽象工厂模式适合扩展产品簇,而又因为难以增加新的产品的特性,抽象工厂模式不适合扩展产品线。