抽象工厂模式(尚硅谷版本)
介绍
- 抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
- 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)
- 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇更利于代码的维护和扩展
实现
【抽象工厂接口】
package com.atguigu.factory.absfactory.pizzastore.order; import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza; /** * 一个抽象工厂模式的抽象层(接口) */ public interface AbsFactory { /** * 让下面的工厂子类来 具体实现 * @param orderType * @return */ public Pizza createPizza(String orderType); }
【工厂子类】
package com.atguigu.factory.absfactory.pizzastore.order; import com.atguigu.factory.absfactory.pizzastore.pizza.BJCheesePizza; import com.atguigu.factory.absfactory.pizzastore.pizza.BJPepperPizza; import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza; //这是工厂子类 public class BJFactory implements AbsFactory { @Override public Pizza createPizza(String orderType) { System.out.println("~使用的是抽象工厂模式~"); Pizza pizza = null; if(orderType.equals("cheese")) { pizza = new BJCheesePizza(); } else if (orderType.equals("pepper")){ pizza = new BJPepperPizza(); } return pizza; } }
package com.atguigu.factory.absfactory.pizzastore.order; import com.atguigu.factory.absfactory.pizzastore.pizza.LDCheesePizza; import com.atguigu.factory.absfactory.pizzastore.pizza.LDPepperPizza; import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza; public class LDFactory implements AbsFactory { @Override public Pizza createPizza(String orderType) { Pizza pizza = null; if (orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } }
【订购】
package com.atguigu.factory.absfactory.pizzastore.order; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza; public class OrderPizza { AbsFactory factory; // 构造器 public OrderPizza(AbsFactory factory) { setFactory(factory); } private void setFactory(AbsFactory factory) { Pizza pizza = null; String orderType = ""; this.factory = factory; do { // 用户输入 orderType = getType(); // factory 可能是北京的工厂子类,也可能是伦敦的工厂子类 pizza = factory.createPizza(orderType); if (pizza != null) { //--if--订购ok pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } else { System.out.println("订购失败"); break; } } while (true); } /** * 写一个方法,可以获取客户希望订购的披萨种类 * @return */ private String getType() { try { BufferedReader strin = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza 种类:"); String str = strin.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } } }
【主类】
package com.atguigu.factory.absfactory.pizzastore.order; public class PizzaStore { public static void main(String[] args) { //new OrderPizza(new BJFactory()); new OrderPizza(new LDFactory()); } }
抽象工厂模式(《图解设计模式》)
介绍
- 抽象工厂将抽象零件组装成为抽象产品,只关心接口,不关心零件的具体实现
- 有多个具体工厂才适合使用抽象工厂模式
案例实现
【抽象类】
package com.atguigu.factory.absfactory.Sample.factory; /** * 抽象工厂 */ public abstract class Factory { /** * 根据指定的类名生成具体工厂的实例 * @param classname * @return */ public static Factory getFactory(String classname) { Factory factory = null; try { //Class.forName动态获取类信息 //使用newInstance()生成类的实例 //new的是具体工厂,后面转成抽象工厂 factory = (Factory)Class.forName(classname).newInstance(); } catch (ClassNotFoundException e) { System.err.println("没有找到 " + classname + "类。"); } catch (Exception e) { e.printStackTrace(); } return factory; } /** * 生成零件 * @param caption * @return */ public abstract Link createLink(String caption, String url); /** * 生成零件 * @param caption * @return */ public abstract Tray createTray(String caption); /** * 生成产品 * @param title * @param author * @return */ public abstract Page createPage(String title, String author); }
package com.atguigu.factory.absfactory.Sample.factory; /** * 项目:Link类和Tray类的父类 */ public abstract class Item { /** * 项目标题 */ protected String caption; public Item(String caption) { this.caption = caption; } /** * 返回HTML文件的内容 * @return */ public abstract String makeHTML(); }
package com.atguigu.factory.absfactory.Sample.factory; /** * 表示HTML的超链接 * 因为Link没有实现Item的抽象方法,因此,Link也是抽象类 */ public abstract class Link extends Item { protected String url; public Link(String caption, String url) { super(caption); this.url = url; } }
package com.atguigu.factory.absfactory.Sample.factory; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; /** * 抽象表示HTML页面(Link和Tray可以理解为抽象零件,Page可以理解为抽象产品) */ public 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); } /** * 1、根据页面标题确认文件名 * 2、调用makeHTML方法将自身保存的HTML内容写入到文件中 */ 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(); }
package com.atguigu.factory.absfactory.Sample.factory; import java.util.ArrayList; /** * 托盘类 * 里面可以包含多个Link和多个Tray,可以理解为上面放置了很多项目 * 没有实现父类的抽象方法,该类也是抽象类 */ public abstract class Tray extends Item { protected ArrayList tray = new ArrayList(); public Tray(String caption) { super(caption); } /** * 添加项目 * @param item */ public void add(Item item) { tray.add(item); } }
【具体工厂一:创建列表形式的页面】
package com.atguigu.factory.absfactory.Sample.listfactory; import com.atguigu.factory.absfactory.Sample.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); } }
package com.atguigu.factory.absfactory.Sample.listfactory; import com.atguigu.factory.absfactory.Sample.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"; } }
package com.atguigu.factory.absfactory.Sample.listfactory; import com.atguigu.factory.absfactory.Sample.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 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(); } }
package com.atguigu.factory.absfactory.Sample.listfactory; import com.atguigu.factory.absfactory.Sample.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 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(); } }
【具体工厂二:创建表格形式的页面】
package com.atguigu.factory.absfactory.Sample.tablefactory; import com.atguigu.factory.absfactory.Sample.factory.*; /** * 多个具体工厂 */ public class TableFactory extends Factory { public Link createLink(String caption, String url) { return new TableLink(caption, url); } public Tray createTray(String caption) { return new TableTray(caption); } public Page createPage(String title, String author) { return new TablePage(title, author); } } package com.atguigu.factory.absfactory.Sample.tablefactory; import com.atguigu.factory.absfactory.Sample.factory.*; public class TableLink extends Link { public TableLink(String caption, String url) { super(caption, url); } public String makeHTML() { return "<td><a href=\"" + url + "\">" + caption + "</a></td>\n"; } }
package com.atguigu.factory.absfactory.Sample.tablefactory; import com.atguigu.factory.absfactory.Sample.factory.*; import java.util.Iterator; public class TablePage extends Page { public TablePage(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("<table width=\"80%\" border=\"3\">\n"); Iterator it = content.iterator(); while (it.hasNext()) { Item item = (Item)it.next(); buffer.append("<tr>" + item.makeHTML() + "</tr>"); } buffer.append("</table>\n"); buffer.append("<hr><address>" + author + "</address>"); buffer.append("</body></html>\n"); return buffer.toString(); } }
package com.atguigu.factory.absfactory.Sample.tablefactory; import com.atguigu.factory.absfactory.Sample.factory.*; import java.util.Iterator; public class TableTray extends Tray { public TableTray(String caption) { super(caption); // 使用super(...)表达式 } public String makeHTML() { StringBuffer buffer = new StringBuffer(); buffer.append("<td>"); buffer.append("<table width=\"100%\" border=\"1\"><tr>"); buffer.append("<td bgcolor=\"#cccccc\" align=\"center\" colspan=\"" + tray.size() + "\"><b>" + caption + "</b></td>"); buffer.append("</tr>\n"); buffer.append("<tr>\n"); Iterator it = tray.iterator(); while (it.hasNext()) { Item item = (Item) it.next(); buffer.append(item.makeHTML()); } buffer.append("</tr></table>"); buffer.append("</td>"); return buffer.toString(); } }
【委托加工】
package com.atguigu.factory.absfactory.Sample; import com.atguigu.factory.absfactory.Sample.factory.*; /** * 使用工厂将零件组装成为产品 * 该类没有使用任何具体零件、产品、工厂,只使用抽象的 */ public class Main { public static void main(String[] args) { String arg = "com.atguigu.factory.absfactory.Sample.listfactory.ListFactory"; //创建工厂 Factory factory = Factory.getFactory(arg); //创建零件 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(); } }
【运行】
LinkPage.html 编写完成。 Process finished with exit code 0
生成的文件(列表形式)
<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>
生成的文件(表格形式)
<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></table></td></tr><tr><td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="3"><b>检索引擎</b></td></tr> <tr> <td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="2"><b>Yahoo!</b></td></tr> <tr> <td><a href="http://www.yahoo.com/">Yahoo!</a></td> <td><a href="http://www.yahoo.co.jp/">Yahoo!Japan</a></td> </tr></table></td><td><a href="http://www.excite.com/">Excite</a></td> <td><a href="http://www.google.com/">Google</a></td> </tr></table></td></tr></table> <hr><address>杨文轩</address></body></html>
角色
AbstractProduct(抽象产品)
:负责定义抽象零件和产品的接口(API),如上面的Link、Tray、Page类AbstractFactory(抽象工厂)
:负责定义生成抽象产品的接口(API),如上面的Factory类Client(委托者)
:委托工厂加工产品,调用AbstractFactory 角色和AbstractProduct角色的接(API),如上面的Main类ConcreteProduct(具体产品)
:负责实现AbstractProduct角色的接口,如上面的ListLink类、ListTray类和ListPage类;TableLink类、TableTray类和TablePage类ConcreteFactory( 具体工厂)
:负责实现AbstractFactory角色的接口,如上面的Listfactory类、Tablefactory类
分析
- 容易增加具体工厂:只需要编写Factory、LinkTray、Page这4个类的子类,实现抽象方法
- 难以增加新零件:如在factory包中增加一个表示图像的Picture零件,需要在抽象工厂中增加一个createPicture的方法,所有的具体工厂都需要新增代码,具体工厂越多,工作量越大
简单工厂模式在JDK中的应用
小结
- 工厂模式的意义:
将实例化对象的代码提取出来,放到一个类中统一管理和维护
,达到和主项目的依赖关系的解耦,从而提高项目的扩展和维护性 - 工厂模式有三种
- 工厂模式体现依赖抽象原则的点:
- 创建对象实例时,不要直接 new 类,而是把这个new 类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用,应该引用抽象类
- 不要让类继承具体类,而是继承抽象类或者是实现interface(接口)
- 不要覆盖基类中已经实现的方法
文章说明
- 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
- 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面