Abstract Factory模式,即抽象工厂模式,该模式要求Factory类为抽象的,并且里面的生产出来的产品也是抽象的!
这里需要着重说的一点就是,抽象类和抽象方法的作用——规范了子类的实现,以及当使用时候,直接可以面向抽象父类/接口的方式进行操作,利用多态的面向对象特性。
同时,需要注意的是,所有抽象的类全都是封装到一个包中的,与调用的不同。
这种方式的一个应用就是JDBC的规范,SUN公司在jdk中提供了相应的接口/抽象父类作为规范,而对应的数据库厂商则根据这个接口/抽象父类去写具体实现。这样一来,我们在操作数据库时候,直接使用sun公司提供的抽象父/接口,而不需要关注具体是怎么实现的,因为不管什么样的数据库,我们操作的代码都是一样的,唯一不同的就是导包不同。
在本次是实例中,使用的一个抽象工厂,以及三个抽象产品。最终希望的就是在E盘的根目录,生成对应的HTML页面。
在factory抽象类的包中,定义了抽象的类
- Factory 抽象的 工厂类
package site.wangxin520.gof.abstractfactory.factory; /** * 抽象工厂的类,制作Link,Tray,Page * 定义了抽象方法,规范了实现该方法的具体工厂类 * @author wangXgnaw * */ public abstract class Factory { /** * 根据实例工厂的全限定名,获取工厂实例,采用反射的方法 * @param factoryName 实例化工厂的全限定名 * @return Factory 返回实例化工厂 */ public static Factory getFactory(String factoryName) { Factory factory=null; try { // factory = (Factory) Class.forName(factoryName).newInstance(); factory = (Factory) ClassLoader.getSystemClassLoader().loadClass(factoryName).newInstance(); } catch (Exception e) { e.printStackTrace(); } return factory; } /** * 抽象类,规范了创建Link和Tray和Page的方法 * @param caption * @param url * @return */ public abstract Link createLink(String caption,String url); public abstract Tray createTray(String caption); public abstract Page createPage(String title,String author); }
- Item 所有产品类的父类
package site.wangxin520.gof.abstractfactory.factory; /** * 方便统一处理Link和Tray的类 * Item类是,Link和Tray的父类 * @author wangXgnaw * */ public abstract class Item { //caption字段表示标题 protected String caption; /** * 构造函数 * @param caption */ public Item(String caption){ this.caption=caption; } /** * 制作html,返回HTML文件的内容 * 本方法是抽象方法,需要子类去实现 * @return String */ public abstract String makeHTML(); }
- Link抽象的工厂中的产品,用于记录超链接的
package site.wangxin520.gof.abstractfactory.factory; /** * Link类抽象的表示HTML的链接的类 * @author wangXgnaw * */ public abstract class Link extends Item{ //url字段保存的是超链接所指向的地址 protected String url; /** * 构造函数,由于继承了一个抽象类,且抽象父类只有一个有参构造 * 所以,构造函数必须提供,并且调用的是父类的有参构造 * @param caption * @param url */ public Link(String caption,String url) { super(caption); this.url=url; } }
- Tray抽象工厂的产品,用于存放元素的
package site.wangxin520.gof.abstractfactory.factory; import java.util.ArrayList; /** * Tray类也要是一个抽象类 * Tray类表示的是一个含有多喝Link类和Tray类的容器 * Tray有托盘的意思 * @author wangXgnaw * */ public abstract class Tray extends Item{ //用于保存Tray和Link类,作为容器 protected ArrayList<Item> tray=new ArrayList<>(); /** * 构造方法,调用父类的有参构造 * @param caption */ public Tray(String caption) { super(caption); } /** * 使用add方法将Link和Tray类集合在一起 * @param item */ public void add(Item item){ tray.add(item); } }
- Page抽象工厂的产品,页面相关
package site.wangxin520.gof.abstractfactory.factory; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; /** * 抽象的表示HTML页面的类 * @author wangXgnaw * */ public abstract class Page { //姓名和作者 protected String title; protected String author; //用于保存页面中的元素 protected ArrayList<Item> content=new ArrayList<>(); /** * page的构造,传入标题和作者 * @param title * @param author */ public Page(String title,String author){ this.title=title; this.author=author; } /** * 在页面中存入元素 * @param item */ public void add(Item item){ content.add(item); } /** * 向文件中写入,这里固定是向E盘根目录中写入一个html文件 */ public void output(){ String filename=title+".html"; FileWriter fw=null; try { fw = new FileWriter(new File("E:/",filename)); fw.write(this.makeHTML()); } catch (IOException e) { e.printStackTrace(); }finally { try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } System.out.println(filename+"编写完成"); } /** * 定义一个制作HTML的方法为子类提供规范 * @return */ public abstract String makeHTML(); }
在其他包中,实现了以上的接口,方便使用
- ListFactory工厂类的具体实现
package site.wangxin520.gof.abstractfactory.listfactory; import site.wangxin520.gof.abstractfactory.factory.Factory; import site.wangxin520.gof.abstractfactory.factory.Link; import site.wangxin520.gof.abstractfactory.factory.Page; import site.wangxin520.gof.abstractfactory.factory.Tray; /** * 表示具体工厂的类 * 制作ListLink,ListTray,ListPage * @author wangXgnaw * */ public class ListFactory extends Factory{ /** * 返回具体的ListLink实例,下同 */ @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); } }
- ListLink上面Link类的具体实现
package site.wangxin520.gof.abstractfactory.listfactory; import site.wangxin520.gof.abstractfactory.factory.Link; /** * 具体零件,表示HTML的连接的类 * @author wangXgnaw * */ 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><br/>"; } }
- ListTray Tray类的具体实现
package site.wangxin520.gof.abstractfactory.listfactory; import site.wangxin520.gof.abstractfactory.factory.Item; import site.wangxin520.gof.abstractfactory.factory.Tray; /** * 具体零件,表示含有Link和Tray的类 * * @author wangXgnaw * */ public class ListTray extends Tray { public ListTray(String caption) { super(caption); } @Override public String makeHTML() { StringBuilder sb = new StringBuilder(); sb.append("<li>").append(caption).append("<ul>"); for (Item item : tray) { sb.append(item.makeHTML()); } sb.append("</ul>").append("</li>"); return sb.toString(); } }
- ListPage Page类的具体实现
package site.wangxin520.gof.abstractfactory.listfactory; import site.wangxin520.gof.abstractfactory.factory.Item; import site.wangxin520.gof.abstractfactory.factory.Page; /** * 具体零件,表示HTML页面的类 * @author wangXgnaw * */ public class ListPage extends Page{ public ListPage(String title, String author) { super(title, author); } @Override public String makeHTML() { StringBuilder sb=new StringBuilder(); sb.append("<html><head><title>"+title+"</title></head>"); sb.append("<body>"); sb.append("<h1>"+title+"</h1>"); sb.append("<ul>"); for (Item item : content) { sb.append(item.makeHTML()); } sb.append("</ul>"); sb.append("<hr>"); sb.append("<address>"+author+"</address>"); sb.append("</body></html>"); return sb.toString(); } }
测试类以及测试方法
package site.wangxin520.gof.abstractfactory; import site.wangxin520.gof.abstractfactory.factory.Factory; import site.wangxin520.gof.abstractfactory.factory.Link; import site.wangxin520.gof.abstractfactory.factory.Page; import site.wangxin520.gof.abstractfactory.factory.Tray; /** * 抽象工厂模式的测试类 * @author wangXgnaw * */ public class Test { public static void main(String[] args){ //获取工厂实体,参数是实体工厂的全限定名 Factory factory=Factory.getFactory("site.wangxin520.gof.abstractfactory.listfactory.ListFactory"); //创建超链接 Link link1 = factory.createLink("王鑫", "http://www.wangxin520.site/"); Link link2 = factory.createLink("淘宝", "https://www.taobao.com/"); Link link3 = factory.createLink("京东", "https://www.jd.com/"); //创建序列,并且将超链接放到序列中 Tray t1 = factory.createTray("主页"); t1.add(link1); Tray t2 = factory.createTray("购物"); t2.add(link2); t2.add(link3); //创建页面,并且将序列放到页面里面 Page page = factory.createPage("首页", "王鑫"); page.add(t1); page.add(t2); //调用page的output()方法去实现写入文件 page.output(); } }
使用抽象工厂的好处:
在这种模式下,增加具体的工厂是很容易的,就像如果有新的数据库厂商过来想要开发,直接让他们实现具体的规范即可。
不过这种模式也是具有缺陷的:
不方便增加新的产品。
实现效果:
- 生成文件
- 打开效果