简介
简单工厂模式(Simple Factory Pattern):定义一个工厂类,可以根据参数返回不同的类的实例,被创建的类的实例通常都有相同的父类。
- 简单工厂模式是根据参数创建实例的模式,创建方法通常是静态方法,也称为静态工厂模式。
结构和实现
- 角色包括:
- 工厂:提供静态方法,创建产品实例。
- 抽象产品:工厂类创建的对象的父类,封装了各种产品的共有方法。
- 具体产品:工厂类创建的对象。
- 结构。
- 静态工厂方法。
public 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;
}
}
- 客户端调用。
- 参数名称可以从配置文件中读取,这样修改参数的时候无需修改源代码,符合开闭原则。
public class Client {
public static void main(String args[]) {
Product product;
product = Factory.getProduct(arg[0]); //通过工厂类创建产品对象
product.methodSame();
product.methodDiff();
}
}
实例
- 开发一套图表库,可以根据参数,提供不同外观的图表,如柱状图、饼状图、折线图等,并可以较为方便的扩展,增加新的图表类型。
- 图表库结构。
- 静态工厂方法。
public class ChartFactory {
public static Chart getChart(String type) {
Chart chart = null;
if (type.equalsIgnoreCase("histogram")) {
chart = new HistogramChart();
//初始化设置柱状图
}
else if (type.equalsIgnoreCase("pie")) {
chart = new PieChart();
//初始化设置饼状图
}
else if (type.equalsIgnoreCase("line")) {
chart = new LineChart();
//初始化设置折线图
}
return chart;
}
}
- 客户端调用。
public class Client {
public static void main(String args[]) {
Chart chart;
//通过静态工厂方法创建产品
chart = ChartFactory.getChart("histogram");
chart.display();
}
}
简单工厂简化
- 可以将抽象产品类和工厂类合并,静态工厂方法放入抽象产品类中。
优缺点和适用环境
- 优点:
- 实现对象的创建和使用分离。工厂类根据参数和逻辑创建对象,客户端只需要使用对象而不需要创建。
- 简化复杂类名。客户端无需知道创建的类名,只需根据参数创建。
- 提高系统灵活性。引入配置文件,可以在不修改客户端源码的情况下更新产生的产品类。
- 缺点:
- 工厂类职责过重。工厂类集中所有的创建逻辑,一旦异常,系统都需要受到影响。
- 增加系统复杂度。增加工厂类这一新的类。
- 扩展困难。增加商品需要修改工厂类,产品较多时工厂逻辑复杂。
- 工厂角色无法实现基于继承的等级结构。使用了静态工厂方法。
- 适用环境:
- 工厂类负责创建的对象较少,不会使工厂方法的逻辑复杂。
- 客户端只知道创建对象的参数,不关心创建过程。
jdk中的应用
- Integer.valueOf。根据int值返回Integer对象。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
- Class.forName。根据类名加载类。
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}