概念:今天,我们将学习23种设计模式的第二种,工厂方法模式,Java 其中最常用的设计模式之一。
定义创建产品对象的工厂界面,将产品对象的实际创建推迟到特定的子工厂类别。这满足了创建模式所需的“创建与使用分离”的特点。
我们称创建的对象为“产品”,创建产品的对象为“工厂”。如果你想创建的产品不多,只要一个工厂类别就可以完成,这种模式被称为“简单的工厂模式”,它不属于 GOF 的 23 一种经典的设计模式,其缺点是在增加新产品时会违反“开闭原则”。
本文介绍的“工厂方法模式”是对简单工厂模式的进一步抽象。其优点是,系统可以在不修改原始代码的情况下引入新产品,即满足开关原则。
特点:- 使用者只需了解特定工厂的名称即可获得所需产品,无需了解产品的具体创建过程。
- 当系统添加新产品时,只需添加特定的产品类别和相应的特定工厂类别,无需修改原工厂,以满足开关原则。
- 抽象工厂(Abstract Factory):通过它,调用器提供了创建产品的界面,以访问特定工厂的工厂方法
new Product()
创造产品。 - 具体工厂(Concrete Factory):主要是实现抽象工厂的抽象方法,创建具体产品。
- 抽象产品(Product):对产品规范进行了定义,描述了产品的主要特点和功能。
- 具体产品(Concrete Product):由具体工厂创建的抽象产品角色定义的接口,与具体工厂一一对应。
- 抽象类图形
package cn.ppdxzz.factorymethod.graph;/** * Description:图形抽象类 */public abstract class Graph { //开始绘制 public abstract void startDraw(); //结束绘制 public abstract void finishDraw();}
- 图形的具体实现类别(这里只列出了小万和小李画圆的实现,重点是对这一设计理念的理解)
package cn.ppdxzz.factorymethod.graph;/** * Description:画圆形的小万 */public class WanCircle extends Graph { @Override public void startDraw() { System.out.println("小万开始画圆形..."); } @Override public void finishDraw() { System.out.println("小万结束画圆形..."); System.out.println("-------------------"); }}
package cn.ppdxzz.factorymethod.graph;/** * Description:小李画圆 */public class LiCircle extends Graph { @Override public void startDraw() { System.out.println("小李开始画圆圈..."); } @Override public void finishDraw() { System.out.println("小李结束画圆形..."); System.out.println("-------------------"); }}
- 抽象绘制图形的实例化功能作为抽象方法,在不同绘制者的子类中具体实现。
package cn.ppdxzz.factorymethod.draw;import cn.ppdxzz.factorymethod.graph.Graph;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;/** * Description:工厂类绘制图形 */public abstract class DrawGraph { //定义绘图抽象方法,让每个工厂的子类实现他们需要绘制的图形 abstract Graph createGraph(String createType); ///构造方法 public DrawGraph() { Graph graph = null; String drawType; do { drawType = getType(); //抽象方法,图形的绘制由工厂子类完成 graph = createGraph(drawType); if (graph != null) { graph.startDraw(); graph.finishDraw(); }else { System.out.println("图形输入错误,已退出!"); break; } }while (true); } ///获取绘制者输入绘制的图形和形状 private String getType() { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("输入绘制的图形:"); try { String str = reader.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return ""; } }}
- 画家小万的具体实现类。
package cn.ppdxzz.factorymethod.draw;import cn.ppdxzz.factorymethod.graph.Graph;import cn.ppdxzz.factorymethod.graph.WanCircle;import cn.ppdxzz.factorymethod.graph.WanRectangle;import cn.ppdxzz.factorymethod.graph.WanTriangle;/** * Description:小万画的图形 */public class DrawWanGraph extends DrawGraph { @Override Graph createGraph(String createType) { Graph graph = null; if ("circle".equals(createType)) { graph = new WanCircle(); }else if ("rectangle".equals(createType)) { graph = new WanRectangle(); }else if ("triangle".equals(createType)){ graph = new WanTriangle(); } return graph; }}
- 画家小李的具体实现类。
package cn.ppdxzz.factorymethod.draw;import cn.ppdxzz.factorymethod.graph.Graph;import cn.ppdxzz.factorymethod.graph.LiCircle;import cn.ppdxzz.factorymethod.graph.LiRectangle;/** * Description:小李画的图形 */public class DrawLiGraph extends DrawGraph { @Override Graph createGraph(String createType) { Graph graph = null; if ("circle".equals(createType)) { graph = new LiCircle(); }else if ("rectangle".equals(createType)){ graph = new LiRectangle(); } return graph; }}
总结:工厂方法模式非常符合“开关原则”。当需要添加新产品时,我们只需要添加特定的产品类别和相应的特定工厂,而无需修改原始系统。同时,在工厂方法模式中,用户只需要知道产品的具体生产工厂可以,不需要关系产品的创建过程,甚至不需要知道具体的产品类别名称。
虽然他很好地遵循了“开关原则”,但每次添加新产品时都需要添加两个类别,这必然会增加系统的复杂性。
这里解释了工厂的方法模式,然后我们将引入另一种设计模式——抽象工厂模式。