抽象工厂的工作是将“抽象零件”组装为“抽象产品”。在抽象工厂模式中将会出现抽象工厂,它会将抽象零件组装为抽象产品。也就是说,我们并不关心零件的具体实现,而是只关心接口。我们仅适用该接口将零件组装起来成为产品。

  

  示例程序的功能是将带有层次关系的链接的集合制作成HTML文件。

 package bigjunoba.bjtu.factory;

 public abstract class Item {
protected String caption; public Item(String caption) {
this.caption = caption;
} public abstract String makeHTML();
}

  Item类是Link类和Tray类的父类。这样,Link类和Tray类就具有可替换性了。caption字段表示项目的“标题”。

 package bigjunoba.bjtu.factory;

 public abstract class Link extends Item {
protected String url; public Link(String caption, String url) {
super(caption);
this.url = url;
}
}

  Link类是抽象地表示HTML的超链接的类。url字段中保存的是超链接所指向的地址。由于Link类中没有实现父类的抽象方法makeHTML,因此它也是抽象类。

 package bigjunoba.bjtu.factory;
import java.util.ArrayList; public abstract class Tray extends Item {
protected ArrayList<Item> tray = new ArrayList<Item>();
public Tray(String caption) {
super(caption);
}
public void add(Item item) {
tray.add(item);
}
}

  Tray类表示的是一个含有多个Link类和Tray类的容器。add方法将Link类和Tray类集合在一起。同理,也没有实现父类的抽象方法makeHTML,因此它也是抽象类。

 package bigjunoba.bjtu.factory;

 import java.io.*;
import java.util.ArrayList; public abstract class Page {
protected String title;
protected String author;
protected ArrayList<Item> content = new ArrayList<Item>(); 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();
}

  Page是抽象地表示HTML页面的类。如果将Link和Tray比喻成抽象的“零件”,那么Page类就是抽象的“产品”。使用add方法向页面中增加Item,output方法首选根据页面标题确定文件名,接着调用makeHTML方法(为了强调调用的是自己的makeHTML方法,直接显式地加上了this)将自身保存的HTML内容写入到文件中。

 package bigjunoba.bjtu.factory;

 public abstract class Factory {
public static Factory getFactory(String classname) {
Factory factory = null;
try {
factory = (Factory)Class.forName(classname).newInstance();
} catch (ClassNotFoundException e) {
System.err.println("没有找到 " + classname + "类。");
} 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);
 }

  Factory类中的getFactory方法,可以根据指定的类名生成具体工厂的实例。getFactory方法通过调用Class类的forName方法来动态地读取类信息,接着使用newInstance方法生成该类的实例,并将其作为返回值返回给调用者。

 package bigjunoba.bjtu.test;

 import bigjunoba.bjtu.factory.*;

 public class Main {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Usage: java Main class.name.of.ConcreteFactory");
System.out.println("Example 1: java Main bigjunoba.bjtu.listfactory.ListFactory");
System.out.println("Example 2: java Main bigjunoba.bjtu.tablefactory.TableFactory");
System.exit(0);
}
Factory factory = Factory.getFactory(args[0]); Link people = factory.createLink("人民日报", "http://www.people.com.cn/");
Link gmw = factory.createLink("光明日报", "http://www.gmw.cn/"); Link us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");
Link jp_yahoo = factory.createLink("Yahoo!Japan", "http://www.yahoo.co.jp/");
Link excite = factory.createLink("Excite", "http://www.excite.com/");
Link google = factory.createLink("Google", "http://www.google.com/"); Tray traynews = factory.createTray("日报");
traynews.add(people);
traynews.add(gmw); Tray trayyahoo = factory.createTray("Yahoo!");
trayyahoo.add(us_yahoo);
trayyahoo.add(jp_yahoo); Tray traysearch = factory.createTray("检索引擎");
traysearch.add(trayyahoo);
traysearch.add(excite);
traysearch.add(google); Page page = factory.createPage("LinkPage", "杨文轩");
page.add(traynews);
page.add(traysearch);
page.output();
}
}

  Main类使用抽象工厂生产零件并将零件组装成产品。由于Main类只引入了一个包,所以可以看出,该类并没有使用任何具体零件、产品和工厂。

 package bigjunoba.bjtu.listfactory;

 import bigjunoba.bjtu.factory.*;

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

  ListFactory类只是简单地new出了ListLink、ListTray和ListPage的实例。

 package bigjunoba.bjtu.listfactory;

 import bigjunoba.bjtu.factory.*;;

 public 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";
}
}

  ListLink类使用<li>和<a>标签来制作HTML片段。

 package bigjunoba.bjtu.listfactory;

 import bigjunoba.bjtu.factory.*;
import java.util.Iterator; public 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<Item> 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();
}
}

  ListTray类中tray字段保存了所有需要以HTML格式输出的Item,而负责将它们以HTML格式输出的就是makeHTML方法。makeHTML方法首先使用<li>标签输出标题,接着使用</ul>和</li>标签输出每个Item。

  每个Item输出为HTML格式的方法就是调用每个Item的makeHTML方法了。这里并不关心变量item中保存的实例的类型究竟是ListLink还是ListTray,只是简单地调用了item.makeHTML()而已。变量item是Item类型的,而Item类又声明了makeHTML方法,而且ListLink类和ListTray类都是Item类的子类,因此可以放心调用。这就是面向对象的优点。

 package bigjunoba.bjtu.listfactory;

 import bigjunoba.bjtu.factory.*;
import java.util.Iterator; public 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<Item> 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();
}
}

  ListPage类和ListTray类差不多。

  当只有一个具体工厂的时候,是完全没有必要划分“抽象类”与“具体类”的。还要增加一个tablefactoty将链接以表格形式展示出来。

  代码结构如上图,这里就不写tablefactory部分的代码了。

<html><head><title>LinkPage</title></head>
<body>
<h1>LinkPage</h1>
<ul>
<li>
日报
<ul>
<li><a href="http://www.people.com.cn/">人民日报</a></li>
<li><a href="http://www.gmw.cn/">光明日报</a></li>
</ul>
</li>
<li>
检索引擎
<ul>
<li>
Yahoo!
<ul>
<li><a href="http://www.yahoo.com/">Yahoo!</a></li>
<li><a href="http://www.yahoo.co.jp/">Yahoo!Japan</a></li>
</ul>
</li>
<li><a href="http://www.excite.com/">Excite</a></li>
<li><a href="http://www.google.com/">Google</a></li>
</ul>
</li>
</ul>
<hr><address>杨文轩</address></body></html>

  执行javac Main.java bigjunoba.bjtu.listfactory/ListFactory.java后的结果如上。

<html><head><title>LinkPage</title></head>
<body>
<h1>LinkPage</h1>
<table width="80%" border="3">
<tr><td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="2"><b>日报</b></td></tr>
<tr>
<td><a href="http://www.people.com.cn/">人民日报</a></td>
<td><a href="http://www.gmw.cn/">光明日报</a></td>
</tr></

  执行javac Main.java bigjunoba.bjtu.tablefactory/TableFactory.java后的结果如上。

  抽象工厂模式的类图。

  抽象工厂的特点:

  1.易于增加具体的工厂。假如要增加新的具体工厂,那么需要做的就是编写Factory、Link、Tray和Page这4个类的子类,并实现它们定义的抽象方法。这样,无论增加多少个具体工厂,都无需修改抽象工厂和Main部分。

  2.难以增加新的零件。假如要在factory包中增加一个表示图像的Picture零件,那就必须要对所有的具体工厂进行相应的修改才行。例如,需要在listfactory包中就必须做到假如createPicture方法和新增ListPictrue类,这样编写完成的具体工厂越多,修改的工作量就会越大。

设计模式(八)Abstract Factory模式的更多相关文章

  1. 【设计模式】Abstract Factory模式

    抽象工厂模式是工厂方法模式的进一步强化.当工厂函数仅仅须要产生一种类型的产品(全部产品都继承自同一抽象基类)时,使用工厂方法模式就可以. 可是.当用户程序须要创建多种类型的产品,而这些产品又有一定的内 ...

  2. 设计模式:abstract factory模式

    含义:抽象工厂将“抽象零件”组装成“抽象产品” 理解:相比于工厂方法模式,可以根据不同的接口创建不同的产品,说白了就是将一个接口变成两个接口,各自返回不同的抽象产品 例子: class Car //抽 ...

  3. 设计模式(3)-对象创建型模式-Abstract Factory模式

    1.对象创建型模式 1.3           Abstract Factory模式 1.3.1 需求 在下面情况能够使用Abstract Factory模式: •  一个系统要独立于它的产品的创建. ...

  4. 设计模式 - Abstract Factory模式(abstract factory pattern) 详细说明

    Abstract Factory模式(abstract factory pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/ ...

  5. 设计模式初学者笔记:Abstract Factory模式

    首先啰嗦下创建迷宫所用的Room类.这个类并不直接保存Room四周的构造,而是通过MapSite* _sides[4]这个私有数组成员指向Room四周的构造.那么什么时候将四周构造直接放在Room中, ...

  6. Java设计模式:Abstract Factory(抽象工厂)模式

    概念定义 抽象工厂(Abstract Factory)模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 抽象工厂模式中,系统的产品有多于一个的产品族(一个产品族里定义多个产品) ...

  7. [学习笔记]设计模式之Abstract Factory

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在上篇笔记Builder设计模式中,时の魔导士祭出了自己的WorldCreator.尽管它因此能创造出一个有山有树有房子的世界,但是白 ...

  8. 设计模式——(Abstract Factory)抽象工厂

    设计模式——(Abstract Factory)抽象工厂 设计面向对象软件比较困难,而设计可复用的面向对象软件就更加困难.你必须设计相关类,并设计类的接口和继承之间的关系.设计必须可以解决当前问题,同 ...

  9. 面向对象设计——抽象工厂(Abstract Factory)模式

    定义 提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类.抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道或关心实际产出的具体产品是什么.这样一来,客户就能从具体的产 ...

  10. 设计模式——(Abstract Factory)抽象工厂“改正为简单工厂”

    设计面向对象软件比较困难,而设计可复用的面向对象软件就更加困难.你必须设计相关类,并设计类的接口和继承之间的关系.设计必须可以解决当前问题,同时必须对将来可能发生的问题和需求也有足够的针对性.掌握面向 ...

随机推荐

  1. 《深度解析Tomcat》 第一章 一个简单的Web服务器

    本章介绍Java Web服务器是如何运行的.从中可以知道Tomcat是如何工作的. 基于Java的Web服务器会使用java.net.Socket类和java.net.ServerSocket类这两个 ...

  2. 前端基于VUE的v-charts的曲线显示

    目录 前端基于VUE的v-charts的曲线显示 1. 应用背景 2. 分析数据生产者生成 3. 取出数据消费者 4. 前端显示 4.1 安装V-charts插件 4.2 引入veline曲线插件 4 ...

  3. (java实现)单向循环链表

    什么是单向循环链表 单向循环链表基本与单向链表相同,唯一的区别就是单向循环链表的尾节点指向的不是null,而是头节点(注意:不是头指针). 因此,单向循环链表的任何节点的下一部分都不存在NULL值. ...

  4. Spring 梳理 - 视图解析器 VS 视图(View,ViewResolver)

    View View接口表示一个响应给用户的视图,例如jsp文件,pdf文件,html文件等 该接口只有两个方法定义,分别表明该视图的ContentType和如何被渲染 Spring中提供了丰富的视图支 ...

  5. 使用 .gitignore 忽略 Git 仓库中的文件

    .gitignore 在Git中,很多时候你只想将代码提交到仓库,而不是将当前文件目录下的文件全部提交到Git仓库中,例如在MacOS系统下面的.DS_Store文件,或者是Xocde的操作记录,又或 ...

  6. Highly Efficient Analysis of Glycoprotein Sialylation in Human Serum by Simultaneous Quantification of Glycosites and Site-Specific Glycoforms (通过同时定量糖基化位点和位点特异性糖型来高效分析人血清中的糖蛋白唾液酸化)-阅读人:陈秋实

    期刊名:Journal of Proteome Research 发表时间:(2019年9月) IF:3.78 单位: 中国科学院大连化学物理研究所 中国科学院大学 大连医科大学第二附属医院 物种:人 ...

  7. node学习笔记(二)流和缓冲区

    内容 视频 第四章内容 菜鸟教程服务器 //复制文件 function de(x) { console.log(x); } var fs=require('fs'); fs.mkdir('stuff' ...

  8. maven私服 nexus 的安装与使用

    简介 私服不是Maven的核心概念,它仅仅是一种衍生出来的特殊的Maven仓库.通过建立自己的私服,就可以降低中央仓库负荷.节省外网带宽.加速Maven构建.自己部署构建等,从而高效地使用Maven. ...

  9. IDEA 学习笔记之 多线程调试

    多线程调试: 在多线程调试的时候,发现一些断点会被跳过,让人很郁闷,然后上网查了下资料,发现是自己IDEA设置不对. 使用IDEA调试多线程的时候,IDEA的断点有不同的模式,只有当Thread模式下 ...

  10. java第4天:String static Arrays类,Math类

    1 字符串的概述和特点 字符串一旦创建,是不可变的. 有双引号的就是字符串 *** 2 字符串的三种构造方法 2-1 第一种: 格式:String str = new String();| :-| 2 ...