设计模式——抽象工厂模式

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();
} }

使用抽象工厂的好处:

在这种模式下,增加具体的工厂是很容易的,就像如果有新的数据库厂商过来想要开发,直接让他们实现具体的规范即可。

不过这种模式也是具有缺陷的:

不方便增加新的产品。

实现效果:

  • 生成文件

设计模式——抽象工厂模式

  • 打开效果

设计模式——抽象工厂模式

上一篇:socket发送http报文的疑惑(求高手指点一二)


下一篇:学习ThinkPHP笔记