简单工厂模式的一种扩展
原创
©著作权归作者所有:来自51CTO博客作者蓝枫居士的原创作品,请联系作者获取转载授权,否则将追究法律责任
关于简单工厂模式的简单介绍请看这里:
同时,这篇博客其实也是对上文的再次扩展。
我们知道简单工厂模式的一个巨大的不足就是
系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
例如经典的工厂代码一般如下:
public 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,就得修改getChart这个类里面的逻辑。而且一堆if else看着实在难受。所以,我可以让每个chart自己判断。
看代码
package simplefactory;
public interface Chart { //总的chart接口
public boolean match(String chart);
public void display();
public void init();
}
package simplefactory;
public class HistogramChart implements Chart { //柱状图的类,饼状图与折线图类似 不再赘述
public HistogramChart() {
System.out.println("创建柱状图!");
}
public void display() {
System.out.println("显示柱状图!");
}
public boolean match(String chart) {
if (chart.equals("hisrogram"))
return true;
return false;
}
@Override
public void init() {
System.out.println("初始化设置柱状图!");
}
}
在这里也有一个xml,如下
其中chartType是所有的chart类型
need 是我们所需要的chart类型
<?xml version="1.0" encoding="UTF-8"?>
<config>
<chartType>simplefactory.HistogramChart</chartType>
<chartType>simplefactory.LineChart</chartType>
<chartType>simplefactory.PieChart</chartType>
<need>line</need>
</config>
分析xml的工具类如下:
package xml;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
public class XMLUtil {
// 该方法用于从XML配置文件中提取图表类型,并返回类型名
// 这个类和上文提到的博客里面的差别在于 方法的参数
public static String[] getChartType(String choice) {
try {
// 创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src/xml/xmlutil.xml"));
// 获取包含图表类型的文本节点
NodeList nl = doc.getElementsByTagName(choice);
String[] names = new String[nl.getLength()];
for (int i = 0; i < nl.getLength(); i++) {
names[i] = nl.item(i).getFirstChild().getNodeValue().trim();
}
return names;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
最后,我们看看重构后的工厂
package simplefactory;
import java.util.ArrayList;
import org.apache.catalina.tribes.membership.StaticMember;
import xml.XMLUtil;
public class ChartFactory {
//产品候选列表
static ArrayList<Chart> charts=new ArrayList<Chart>();
//需要的产品
static String[] choise=new String[1];
public static Chart getChart(){
charts=ChartFactory.getAllChart();
choise=XMLUtil.getChartType("need");
for (int i = 0; i < charts.size(); i++)
if (charts.get(i).match(choise[0]))
return charts.get(i);
return null;
}
public static ArrayList<Chart> getAllChart() {
//获得所有chart的路径
String[] name = XMLUtil.getChartType("chartType");
ArrayList<Chart> chart = new ArrayList<Chart>();
try {
//将chart全部new出来
for (int i = 0; i < name.length; i++)
chart.add((Chart) Class.forName(name[i]).newInstance());
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return chart;
}
}
测试如下
package simplefactory;
public class ChartTest {
public static void main(String[] args) {
Chart chart=ChartFactory.getChart();
System.out.println("------");
chart.init();
chart.display();
}
}
结果如下:
创建柱状图!
创建折线图!
创建饼状图!
------
初始化设置折线图!
显示折线图!
如果想要饼状图,只需要把xml改成
<need>pie</need>
总结一下:
我现在已经不能说这次重构的结果仍然是工厂模式了。工厂模式是生产一个匹配于所给参数的产品。而我这个等于是把工厂支持的产品先都生产出来,再一个一个问:人家需要的是这个产品,你看你行不?
好处就在于,以后即使要扩展新的产品,只用改xml就好。不用对工厂做改变。
而且我们告别了一大堆if else。
感谢glt