简单工厂

一,概述

简单工厂:一个工厂类根据传入的参量决定创建出那一种产品类的实例。

简单工厂模式结构比较简单,其核心是工厂类的设计,其结构如图1所示:

在简单工厂模式结构图中包含如下几个角色:

       ● Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product。

       ● Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。

       ● ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。

典型的抽象产品类代码如下所示:

abstract class Product {
    //所有产品类的公共业务方法
    public void methodSame() {
        //公共方法的实现
    }
 
    //声明抽象业务方法
    public abstract void methodDiff();
}

典型的具体产品类代码如下所示:

class ConcreteProduct extends Product {
    //实现业务方法
    public void methodDiff() {
        //业务方法的实现
    }
}

 

典型的工厂类代码如下所示:

class Factory {
    //静态工厂方法
    public static Product getProduct(String arg) {
        Product product = null;
        if (arg.equalsIgnoreCase("A")) {
            product = new ConcreteProductA();
            //初始化设置product
        }
        else if (arg.equalsIgnoreCase("B")) {
            product = new ConcreteProductB();
            //初始化设置product
        }
        return product;
    }
}

在客户端代码中,我们通过调用工厂类的工厂方法即可得到产品对象,典型代码如下所示:

class Client {
    public static void main(String args[]) {
        Product product; 
        product = Factory.getProduct("A"); //通过工厂类创建产品对象
        product.methodSame();
        product.methodDiff();
    }
}

二,实例:

使用简单工厂模式对图表库进行重构,重构后的结构如图2所示:

 

  在图2中,Chart接口充当抽象产品类,其子类HistogramChart、PieChart和LineChart充当具体产品类,ChartFactory充当工厂类。完整代码如下所示:

//抽象图表接口:抽象产品类
interface Chart {
    public void display();
}
 
//柱状图类:具体产品类
class HistogramChart implements Chart {
    public HistogramChart() {
        System.out.println("创建柱状图!");
    }
    
    public void display() {
        System.out.println("显示柱状图!");
    }
}
 
//饼状图类:具体产品类
class PieChart implements Chart {
    public PieChart() {
        System.out.println("创建饼状图!");
    }
    
    public void display() {
        System.out.println("显示饼状图!");
    }
}
 
//折线图类:具体产品类
class LineChart implements Chart {
    public LineChart() {
        System.out.println("创建折线图!");
    }
    
    public void display() {
        System.out.println("显示折线图!");
    }
}
 
//图表工厂类:工厂类
class ChartFactory {
    //静态工厂方法
    public static Chart getChart(String type) {
        Chart chart = null;
        if (type.equalsIgnoreCase("histogram")) {
            chart = new HistogramChart();
            System.out.println("初始化设置柱状图!");
        }
        else if (type.equalsIgnoreCase("pie")) {
            chart = new PieChart();
            System.out.println("初始化设置饼状图!");
        }
        else if (type.equalsIgnoreCase("line")) {
            chart = new LineChart();
            System.out.println("初始化设置折线图!");            
        }
        return chart;
    }
}

在客户端测试类中,我们使用工厂类的静态工厂方法创建产品对象,如果需要更换产品,只需修改静态工厂方法中的参数即可,例如将柱状图改为饼状图,只需将代码:

chart = ChartFactory.getChart("histogram");

       改为:

chart = ChartFactory.getChart("pie");

三,方案的改进:每更换一个Chart对象都需要修改客户端代码中静态工厂方法的参数,客户端代码将要重新编译,这对于客户端而言,违反了“开闭原则”

我们可以将静态工厂方法的参数存储在XML或properties格式的配置文件中,如下config.xml所示:

<?xml version="1.0"?>
<config>
    <chartType>histogram</chartType>
</config>

再通过一个工具类XMLUtil来读取配置文件中的字符串参数,XMLUtil类的代码如下所示:

import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
 
public class XMLUtil {
    //该方法用于从XML配置文件中提取图表类型,并返回类型名
    public static String getChartType() {
        try {
            //创建文档对象
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;                            
            doc = builder.parse(new File("config.xml")); 
        
            //获取包含图表类型的文本节点
            NodeList nl = doc.getElementsByTagName("chartType");
            Node classNode = nl.item(0).getFirstChild();
            String chartType = classNode.getNodeValue().trim();
            return chartType;
        }   
           catch(Exception e) {
               e.printStackTrace();
            return null;
        }
    }
}

在引入了配置文件和工具类XMLUtil之后,客户端代码修改如下:

class Client {
    public static void main(String args[]) {
        Chart chart;
        String type = XMLUtil.getChartType(); //读取配置文件中的参数
        chart = ChartFactory.getChart(type); //创建产品对象
        chart.display();
    }
}

不难发现,在上述客户端代码中不包含任何与具体图表对象相关的信息,如果需要更换具体图表对象,只需修改配置文件config.xml,无须修改任何源代码,符合“开闭原则”。

posted @ 2019-01-08 20:08  Archer-Fang  阅读(268)  评论(0编辑  收藏  举报