一、前言
上次我们学习了Builder模式,用来组装复杂的实例,Builder就是我们盖房子的一块块砖头,钢筋和水泥,以及简单的用法,使用监工将这些元素有机的组合在了一起就能够建造整个建筑了,是监工将这些原材料按照一定的次序和特定的处理流程糅合在一起,这个过程就是组装。而现在我们学习了抽象工厂模式,将关键零件组装成产品。
在此之前,让我们对前面的几种模式做简单的回顾,首先我们学习了迭代器模式,使用了工厂方法创造迭代器,并且完成了元素的内部实现和遍历的分离,因此成为“器”,也算是一种配合,其次我们学习了适配器,有类适配器和对象适配器,这两者只是实现的方式不同,本质是一样的,都是通过在原素材上加入一个适配器使得能够满足现在的需要,一般用在版本之间的兼容上使得新版本的内容能够在旧版本上使用(适配),以及一些复用的时候需要适当的修改(适配)的场合;之后我们学习了模板模式和工厂模式,模板方法的一个特殊实现其实就是工厂方法,模板方法就是通过在父类之中定义职责,然后让子类实现各自的子任务,最后通过父类进行调用,提高了代码的可修改性和可扩展性,工厂方法则是在模板方法的基础上,通过生产产品的方式将框架的实现分离,遵循了高内聚低耦合的原则;在之后我们学习了单例模式和原型模式,单例模式是保证全局关于某个类只有一个对象,在某些多线程或者编码误用的条件下非常重要,原型模式则是实现了对象的深浅拷贝,使得经过了很长时间才得到的对象能够保存以及复制和使用,省去了很多不必要的new操作。之后我们学习了Builder模式,通过增加一个监工类来将父类中定义的方法组合起来实现某种功能,实现了类的隔离,便于代码的复用,是模板模式的升级版。
学习了这么多模式,不知道大家对设计模式有没有什么感悟,可以说就是通过接口、抽象类。继承、多态等机制遵循高内聚低耦合、封闭原则、里式代换原则等实现代码的可复用性,可扩展性,尽管比以前变得复杂了,其实成都越大扩展就越简单。那么为什么又是抽象工厂模式呢?
抽象工厂模式是一个非常复杂的模式,和工厂方法键值差别太大了,但是也有相同之处,那就是抽象工厂也是用了工厂方法来创造产品,只不过抽象工厂模式中包含了零件、产品、工厂、抽象等概念,这样就非常的复杂了,一般还要用到模板方法、迭代器甚至原型模板等,就“抽象”两个字来说,就是将所有的角色分成两部分,一部分是这个角色的抽象类,另一部分是这个角色的实现类,工厂就是沿用了工厂模式,因此抽象工厂模式分为两大部分,抽象部分和具体实现部分,如图所示:
上面的抽象部分,最重要的就是抽象的工厂类(Link)、抽象的零件类(Tray)、抽象的产品类(Page),这两个零件有共同之处,因此通过item类进行抽象便于两者之间的互通。下面的具体实现部分即使对抽象的实现了,之后我们使用main类来进行整合,可以发现我们只用对抽象类进行编程,完全不用使用任何的具体类就能实现我们想要的功能,甚至导致编译器在编译的时候还需要指出需要编译的具体类,因为我们使用了Class.forName()方法实现了反射。这样的结构看似非常的庞大,其实仔细的推敲,反而妙趣横生,当我们还想创建一个具体的工厂的时候实在是太简单了,原来抽象工厂的代码都不用修改,只用按照响应的抽象实现就可以了,之后我们就可以直接使用了,只用在main中将Class.forName()所指定的类改一下就可以了,非常的方便。凡是有利就有弊,如果我们对抽象工厂中的某些定义不满意了呢,这个时候如果我们对抽象方法进行一定的调整和更改(增加或删除),那么所有实现了该抽象工厂的具体工厂的类都需要进行修改,如果有100个具体工厂,无疑是非常可怕的,因此我们应该理智的取舍,废话少说,让我们看一下代码。
二、代码实现
我们将类分成三个部分,这样思路更加清晰,第一部分是抽象工厂中的类,第二部分是具体实现的具体工厂类,第三部分是测试使用的Main类。
抽象工厂包:
Item 抽象类:
package designMode.abstractfactory.factory;
public abstract class Item {
protected String caption;
public Item(String caption){
this.caption=caption;
}
public abstract String makeHTML();
}
Link抽象类:
package designMode.abstractfactory.factory;
public abstract class Link extends Item{
public String url;
public Link(String caption,String url) {
super(caption);
this.url = url;
}
}
Tray抽象类:
package designMode.abstractfactory.factory;
import java.util.ArrayList;
public class Tray extends Item {
protected ArrayList items = new ArrayList();
public Tray(String caption) {
super(caption);
}
@Override
public String makeHTML() {
return null;
}
public void add(Item item){
items.add(item);
}
}
Page抽象类:
package designMode.abstractfactory.factory;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
public abstract class Page {
protected String title;
protected String author;
protected ArrayList content = new ArrayList();
public Page(String title,String author) {
this.author = author;
this.title=title;
}
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();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("写入文件:"+filename+"已成功!");
}
public abstract String makeHTML() ;
}
Factory工厂抽象类:
package designMode.abstractfactory.factory;
//Factory工厂抽象类:
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();
}
return factory;
}
public abstract Link createLink(String caption,String url);
public abstract Tray createTray(String caption);
public abstract Page createPage(String title,String author);
}
具体实现工厂类:
ListLink类:
package designMode.abstractfactory.listfactory;
import designMode.abstractfactory.factory.Link;
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类:(迭代器模式)ArrayList本身实现了迭代器。
package designMode.abstractfactory.listfactory;
import designMode.abstractfactory.factory.Item;
import designMode.abstractfactory.factory.Tray;
import java.util.Iterator;
public class ListTray extends Tray {
public ListTray(String caption) {
super(caption);
}
public String makeHTML() {
StringBuffer sb=new StringBuffer();
sb.append("<li>\n");
sb.append(caption+"\n");
sb.append("<ul>\n");
Iterator it=items.iterator();
while(it.hasNext()){
Item item=(Item)it.next();
sb.append(item.makeHTML());
}
sb.append("</ul>\n");
sb.append("</li>\n");
return sb.toString();
}
}
ListPage类:(迭代器模式)ArrayList本身实现了迭代器。
package designMode.abstractfactory.listfactory;
import designMode.abstractfactory.factory.Item;
import designMode.abstractfactory.factory.Page;
import java.util.Iterator;
public class ListPage extends Page {
public ListPage(String title, String autor) {
super(title, autor);
}
@Override
public String makeHTML() {
StringBuffer sb=new StringBuffer();
sb.append("<html><head><title>"+title+"</title></head>");
sb.append("<body>\n");
sb.append("<h1>"+title+"</h1>");
sb.append("<ul>\n");
Iterator it=content.iterator();
while(it.hasNext()){
Item item=(Item)it.next();
sb.append(item.makeHTML());
}
sb.append("</ul>\n");
sb.append("<hr><address>"+author+"</address>");
sb.append("</body></html>\n");
return sb.toString();
}
}
ListFactory类:(工厂方法模式)
package designMode.abstractfactory.listfactory; import designMode.abstractfactory.factory.Factory; import designMode.abstractfactory.factory.Link; import designMode.abstractfactory.factory.Page; import designMode.abstractfactory.factory.Tray; 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); } }
Main类:
package designMode.abstractfactory.test; import designMode.abstractfactory.factory.Factory; import designMode.abstractfactory.factory.Link; import designMode.abstractfactory.factory.Page; import designMode.abstractfactory.factory.Tray; public class Main { public static void main(String[] args) { String[] choice = {"designMode.abstractfactory.listfactory.listFactory.ListFactory"}; Factory factory = Factory.getFactory(choice[0]); Tray tray_life=factory.createTray("我的生活"); Link link_graduate=factory.createLink("我的本科", "http://www.swjtu.edu.cn"); Link link_postgraduate=factory.createLink("我的研究生","http://www.uestc.edu.cn"); tray_life.add(link_graduate); tray_life.add(link_postgraduate); Tray tray_blog=factory.createTray("我的博客"); Link link_iterator=factory.createLink("迭代器","https://www.cnblogs.com/zyrblog/p/9217673.html"); Link link_adapter=factory.createLink("适配器", "https://www.cnblogs.com/zyrblog/p/9218316.html"); tray_blog.add(link_iterator); tray_blog.add(link_adapter); Tray tray_blog_all=factory.createTray("博客园"); Link link_other1=factory.createLink("解释器模式", "https://www.cnblogs.com/Answer-Geng/p/9231042.html"); Link link_other2=factory.createLink("OAuth 2.0", "https://www.cnblogs.com/cjsblog/p/9230990.html"); tray_blog_all.add(tray_blog); tray_blog_all.add(link_other1); tray_blog_all.add(link_other2); Page page=factory.createPage("zyr", "朱彦荣"); page.add(tray_life); page.add(tray_blog_all); page.output(); } }
可以看到完全组成了一个网页。看到这里大家可能很质疑,难道废了这么大的功夫就是为了实现这么简单的功能?其实这里我们可以看到抽象工厂的强大之处,零件的组装与嵌套,相互关联,通过迭代器、模板模式、工厂模式等最终实现了这种功能,可扩展性非常强大,如果还要生成其它种类的工厂,将非常的方便,直接写实现类就可以了,其它代码基本不需要改动,这样的功能可以说非常强大了,至今为止我们很多的代码都是强耦合的,很难实现复用,而这个抽象的工厂模式就可以实现高层次的复用,只需要知道实现类的类名就可以执行了,我们完全可以实现其他工厂,从而实现其他的功能。抽象工厂模式最重要的就是可复用性和完美的隔离性,其中使用了makeHTML()很多次,通过迭代器来展现了这个方法的多台。灵活使用抽象工厂模式可以说是设计模式真正入门的起点。抽象工厂将抽象零件组装成抽象产品,易于增加具体的工厂难于增加新的零件。