简单工厂设计模式
概念
简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
角色
- 工厂角色
简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。- 抽象产品角色
简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。- 具体产品角色
是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
UML图如下
简单工厂模式的优缺点
优点
- 工厂类包含必要的判断逻辑,可以决定在什么时候创建那个产品的实例,客户端可以免除直接创建对象的职责,而仅仅消费产品,实现了对象创建和使用的分离
- 客户端无需知道所创建的产品的具体类名,只需要知道产品类对应的不同参数即可
- 可以引入配置文件,在不修改客户端代码的情况下更换和新增具体的产品类
缺点
- 工厂类职责过重,一旦不能正常工作,整个系统都要受到影响
- 会增加系统中类的个数,增加了系统的复杂度和理解难度
- 系统扩展困难,一旦添加新产品类,就不得不修改逻辑工厂
- 使用静态工厂方法,不能形成基于继承的等级结构
适合环境
- 工厂类负责创建的对象较少,不会使得工厂的逻辑过于复杂
- 客户端只需要知道传入工厂的参数,而不需要关心对象如何创建
例子
某公司需要基于java开发一套图表工具,可以提供不同的图表如:柱状图(HistogramChart),饼状图(PieChart),折线图(LineChart)。该公司需要我们为其提供一套灵活的图标库,通过传入不同的参数得到不同的图表来使用。
分析
我们先将实体与简单工厂的角色一一对应
- 抽象产品角色: Chart
- 具体产品角色: HistogramChart,PieChart,LineChart
- 工厂角色: ChartFactory
看不懂不要紧,我们先看UML图,在看代码应该就能理解了
编码
Chart.java
package cn.kevinlu98.simplefactory;
/**
* @Author: Kevin·Lu
* @Date: 8:26 PM 2019/7/25
* @Description:抽象图表接口,充当抽象的产品类
*/
public interface Chart {
public static final String CHART_HISTOGRAM = "histogram";
public static final String CHART_PIE = "pie";
public static final String CHART_LINE = "line";
public void display();
}
HistogramChart.java
package cn.kevinlu98.simplefactory;
/**
* @Author: Kevin·Lu
* @Date: 8:29 PM 2019/7/25
* @Description: 柱状图,充当具体的产品
*/
public class HistogramChart implements Chart {
public HistogramChart() {
System.out.println("创建柱状图");
}
@Override
public void display() {
System.out.println("显示柱状图");
}
}
LineChart.java
package cn.kevinlu98.simplefactory;
/**
* @Author: Kevin·Lu
* @Date: 8:32 PM 2019/7/25
* @Description: 折线图类,充当具体的产品类
*/
public class LineChart implements Chart {
public LineChart() {
System.out.println("创建折线图");
}
@Override
public void display() {
System.out.println("显示折线图");
}
}
PieChart.java
package cn.kevinlu98.simplefactory;
/**
* @Author: Kevin·Lu
* @Date: 8:31 PM 2019/7/25
* @Description: 饼状图类,充当具体的产品类
*/
public class PieChart implements Chart {
public PieChart() {
System.out.println("创建了饼状图");
}
@Override
public void display() {
System.out.println("显示饼状图");
}
}
ChartFactory.java
package cn.kevinlu98.simplefactory;
/**
* @Author: Kevin·Lu
* @Date: 8:34 PM 2019/7/25
* @Description: 图表工厂,充当工厂类
*/
public class ChartFactory {
/**
* 静态工厂方法
*
* @param type
* @return
*/
public static Chart getChart(String type) {
Chart chart = null;
if (type.equalsIgnoreCase(Chart.CHART_HISTOGRAM)) {
chart = new HistogramChart();
System.out.println("初始化设置柱状图");
} else if (type.equalsIgnoreCase(Chart.CHART_PIE)) {
chart = new PieChart();
System.out.println("初始化设置饼状图");
} else if (type.equalsIgnoreCase(Chart.CHART_LINE)) {
chart = new LineChart();
System.out.println("初始化设置折线图");
}
return chart;
}
}
Client.java
package cn.kevinlu98.simplefactory;
/**
* @Author: Kevin·Lu
* @Date: 8:38 PM 2019/7/25
* @Description: 简单工厂模式 客户端测试
*/
public class Client {
public static void main(String[] args) {
String type = "histogram";
Chart chart = ChartFactory.getChart(type);
chart.display();
}
}
运行结果
我们需要不同的图表时只需要更改客户端的type变量的值就可以了
优化
不难发现我们像上面那样设计的程序必须通过修改客户端中的main方法的type变量的值来进行创建不同的图表,代码一旦更改就需要重新编译,违反了开闭原则
我们可以通过一种常用的方法解决,让客户端不更改代码的前提下更换具体的对象
在java语言中常用的配置就是XML了
创建config.xml
<?xml version="1.0" encoding="utf-8" ?>
<config>
<chartType>line</chartType>
</config>
编写XML工具类,XMLUtil.java
package cn.kevinlu98.simplefactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
/**
* @Author: Kevin·Lu
* @Date: 8:41 PM 2019/7/25
* @Description: 读取xml文件中的字符串参数
*/
public class XMLUtil {
public static String getChartType() {
try {
//创建文档对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("src/cn/kevinlu98/simplefactory/config.xml"));
//获取包含图表类型的文本节点
NodeList nl = document.getElementsByTagName("chartType");
Node classNode = nl.item(0).getFirstChild();
String chartType = classNode.getNodeValue();
return chartType;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
修改客户端代码,Client.java
package cn.kevinlu98.simplefactory;
/**
* @Author: Kevin·Lu
* @Date: 8:38 PM 2019/7/25
* @Description: 简单工厂模式 客户端测试
*/
public class Client {
public static void main(String[] args) {
String type = XMLUtil.getChartType();
Chart chart = ChartFactory.getChart(type);
chart.display();
}
}
重新运行
现在我们需要更换对象时只需要在XML中配置就好了
至此,简单工厂设计模式介绍完成,希望能帮助到您