【自分の総括】设计模式之简单工厂模式(实例分析)

来源:互联网 发布:免费发送短信软件 编辑:程序博客网 时间:2024/04/30 07:47

一、概念

定义一个工厂类,根据参数的不同返回不同类的实例,这些类具有公共的父类和一些公共的方法。简单工厂模式不属于GoF设计模式,是最简单的工厂模式。在分析简单工厂模式中,引入三个角色概念。Factory(工厂角色)、Product(抽象产品角色)、ConcreteProduct(具体产品角色)。


二、实例分析

背景简单引入,系统提供三个具体产品类分别对应三种图表的打印,三个具体产品类实现同一个抽象产品接口,创建一个工厂类用于区分需要返回的具体产品类,标识用户当前需要打印的图表种类。

1.抽象产品接口

//abstract product interfacepublic interface Chart {public void display();}
2.三个具体产品类
// concrete product class No.1public class HistogramChart implements Chart {public HistogramChart() {System.out.println("Create HistogramChart!");}public void display() {System.out.println("Display HistogramChart!");}}
//concrete product class No.2public class LineChart implements Chart {public LineChart() {System.out.println("Create LineChart!");}public void display() {System.out.println("Display LineChart!");}}
//concrete product class No.3public class PieChart implements Chart {public PieChart() {System.out.println("Create PieChart!");}public void display() {System.out.println("Display PieChart!");}}
3.简单工厂类
工厂类是简单工厂模式的核心,提供一个static方法用于返回具体产品类的对象,返回对象是抽象产品类型,这也是定义一个公共产品接口的好处。假如如不这么设计,而是将产品类直接平铺开,会有造成什么影响?
// simple factorypublic class ChartFactory {public static Chart getChart(String type) {Chart chart = null;if (type.equalsIgnoreCase("histogram")) {chart = new HistogramChart();System.out.println("Initialization HistogramChart...");} else if (type.equalsIgnoreCase("pie")) {chart = new PieChart();System.out.println("Initialization LineChart...");} else if (type.equalsIgnoreCase("line")) {chart = new LineChart();System.out.println("Initialization PieChart...");}return chart;}}
4.用于测试的客户端类
定义一个抽象产品类型的对象,调用工厂方法、传入参数即可得到返回的具体产品实例。假如没有抽象产品角色(Chart),客户端的代码也会变得复杂难编写。在这里,客户端免除了直接创建产品对象的责任,而仅仅使用产品。
public class Client {public static void main(String args[]) {Chart chart = null;// take histogram as examplechart = ChartFactory.getChart("histogram");// other chart have similar effectchart.display();}}
控制台输出结果:
Create HistogramChart!Initialization HistogramChart...Display HistogramChart!
5.分析
简单工厂模式实现了对责任的划分,将产品的创建和使用划分开。
工厂类集中了所有产品的创建逻辑,一旦出错,整个系统都会受到影响。
追加或删除产品时都需要修改工厂逻辑,系统扩展较为困难,违反开闭原则。
开闭原则:软件实体应对扩展开放,而对修改关闭。

if ... else ...语句可能过多造成代码冗长。


三、实例优化

在客户端创建具体产品对象时,每更换一个产品对象时都需要修改客户端代码中静态工厂方法的参数,需要重新编译,这对客户端而言,违反开闭原则。有过开发经验的人看到此,可能已经想到不止一种的解决办法。以下是将需要传入静态工厂方法的参数存储在一份XML文件config.xml中:

<?xml version="1.0"?>  <config>      <chartType>histogram</chartType>  </config>
追加一个工具类XMLUtil来读取XML文件的字符串参数:
import javax.xml.parsers.*;import org.w3c.dom.*;import java.io.*;public class XMLUtil {// get target string from xmlfile and return to clientpublic static String getChartType() {try {// create document objectDocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc = builder.parse(new File("config.xml"));// get targetString's node// list be used yet get only one valueNodeList nl = doc.getElementsByTagName("chartType");Node classNode = nl.item(0).getFirstChild();String chartType = classNode.getNodeValue().trim();return chartType;} catch (Exception e) {e.printStackTrace();return null;}}}
重新编写客户端类:
public class Client {public static void main(String args[]) {Chart chart;          String type = XMLUtil.getChartType();// read targetString in the xmlFile        chart = ChartFactory.getChart(type);// create product object        chart.display();}}
至此,当用户需要更换产品类时,只需要修改配置文件中的字符串值,无需对Java代码修改,符合开闭原则。

四、简单工厂模式简化

为了简化简单工厂模式,可以将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中,这种做法在JDK等类库和框架中也广泛存在。
为了合并抽象产品类和工厂类,抽象产品角色需要写成抽象类,不能是接口,毕竟接口内没法写静态方法。

修改后的抽象产品类:

public abstract class Chart {abstract void display();public static Chart getChart(String type) {Chart chart = null;if (type.equalsIgnoreCase("histogram")) {chart = new HistogramChart();System.out.println("Initialization HistogramChart...");} else if (type.equalsIgnoreCase("pie")) {chart = new PieChart();System.out.println("Initialization LineChart...");} else if (type.equalsIgnoreCase("line")) {chart = new LineChart();System.out.println("Initialization PieChart...");}return chart;}}
客户端测试类:
public class Client {public static void main(String args[]) {Chart chart;          String type = XMLUtil.getChartType();// read targetString in the xmlFile        chart = Chart.getChart(type);// create product object        chart.display();}}


五、总结

简单工厂模式提供了专门的工厂类用于创建对象,将对象的创建和对象的使用分离开,它作为一种最简单的工厂模式在软件开发中得到了较为广泛的应用。
优点:
1.工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。

2.客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。

3.通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

缺点:

1.由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。

2. 使用简单工厂模式势必会增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度。

3.系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。

4.简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

适用场景:

1.工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。

2.客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

0 0