在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式来代替。
复杂对象指的是类的构造函数参数过多等对类的构造有影响的情况,因为类的构造过于复杂,如果直接在其他业务类内使用,则两者的耦合过重,后续业务更改,就需要在任何引用该类的源代码内进行更改,光是查找所有依赖就很消耗时间了,更别说要一个一个修改了。
工厂模式的定义:
是指定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”
的特点。
按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别是
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
简单工厂模式(Simple Factory Pattern)
,又叫作静态工厂方法模式(Static Factory Method Pattern)。
我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。
简单来说,简单工厂模式有一个具体的工厂类,可以生成多个不同的产品,属于创建型设计模式。
简单工厂模式不在 GoF 23 种设计模式之列。
(1)简单工厂模式主要 3个角色
- 简单工厂(SimpleFactory): 是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的-建产品类的方法可以被外界直接调用,创建所需的产品对象。
- 抽象产品(Product): 是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
- 具体产品(ConcreteProduct): 是简单工厂模式的创建目标。
(2)结构图如下:(图来自网络)
主要优点:
- 结构简单,调用方便。工厂和产品的职责区分明确。
- 客户端无需知道所创建具体产品的类名,只需知道参数即可。
主要缺点:
- 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
5、在框架源码中使用也很广泛- JDK源码中的 Calendar.getInstance()方法
- Logback源码中多个重载的 getLogger()方法
代码如下:
public class SimpleFactoryPattern {
public static void main(String[] args) {
Product product = SimpleFactory.makeProduct(2);
product.show();
}
//抽象产品
public interface Product {
void show();
}
//具体产品:ProductA
static class ConcreteProduct1 implements Product {
@Override
public void show() {
System.out.println("具体产品1显示...");
}
}
//具体产品:ProductB
static class ConcreteProduct2 implements Product {
@Override
public void show() {
System.out.println("具体产品2显示...");
}
}
//具体产品:ProductC
static class ConcreteProduct3 implements Product {
@Override
public void show() {
System.out.println("具体产品3显示...");
}
}
final class Const {
static final int PRODUCT_A = 0;
static final int PRODUCT_B = 1;
static final int PRODUCT_C = 2;
}
static class SimpleFactory {
public static Product makeProduct(int kind) {
switch (kind) {
case Const.PRODUCT_A:
return new ConcreteProduct1();
case Const.PRODUCT_B:
return new ConcreteProduct2();
case Const.PRODUCT_C:
return new ConcreteProduct3();
}
return null;
}
}
}
三、模式的应用实例
简易计算器为例,需求:输入两个数和运算符,得到结果。
1、抽象产品
public abstract class Operation {
protected abstract double compute (double number1, double number2) throws Exception;
}
2、具体产品
- 加法
public class OperationAdd extends Operation{
@Override
protected double compute(double number1, double number2) {
return number1 + number2;
}
}
- 减法
public class OperationSub extends Operation{
@Override
protected double compute(double number1, double number2) {
return number1 - number2;
}
}
- 乘法
public class OperationMul extends Operation{
@Override
protected double compute(double number1, double number2) {
return number1 * number2;
}
}
- 除法
public class OperationDiv extends Operation{
@Override
protected double compute(double number1, double number2) throws Exception {
if(number2 == 0){
throw new Exception("除数不能为0!");
}
return number1 / number2;
}
}
3、简单工厂
这里对简单工厂创建产品进行了优化,可以通过缓存、配置文件、反射和泛型等技术了优化。
如果运算业务需要扩展,需要创建具体运算类即可,不需要再修改简单工厂类了。
public class OperationFactory {
private static final Map cachedParsers = new HashMap();
static {
cachedParsers.put("+", new OperationAdd());
cachedParsers.put("-", new OperationSub());
cachedParsers.put("*", new OperationMul());
cachedParsers.put("/", new OperationDiv());
}
public static Operation createOperate0(String operate) {
if (operate == null || operate.isEmpty()) {
return null;//返回null还是IllegalArgumentException全凭你自己说了算
}
return cachedParsers.get(operate);
}
/**
* createOperate0运用缓存技术,节省内存和对象创建的时间
* createOperate0 和 createOperate1 同理
*/
public static Operation createOperate1(String operate){
Operation operation = null;
switch (operate){
case "+":
operation = new OperationAdd(); break;
case "-":
operation = new OperationSub(); break;
case "*":
operation = new OperationMul(); break;
case "/":
operation = new OperationDiv(); break;
}
return operation;
}
/**
* createOperate1方法不符合开闭原则
* 如果运算业务继续扩展,需要创建具体运算类,也需要修改简单工厂的 createOperate1方法。
* 采用反射技术进行优化,即createOperate2方法
*/
public static Operation createOperate2(String className){
Operation operation = null;
try {
if(!(null == className || "".equals(className))){
operation = (Operation) Class.forName(className).newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return operation;
}
/**
* createOperate2方法中类型强制转型,参数为字符串,可控性不高
* 采用反射和泛型技术进行优化,即createOperate3方法
*/
public static Operation createOperate3(Class clazz){
try {
if(null != clazz){
return clazz.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
4、测试
public class Test {
public static void main(String[] args) throws Exception {
double num1 = 10;
double num2 = 2;
System.out.println(OperationFactory.createOperate0("*").compute(num1, num2));
System.out.println(OperationFactory.createOperate1("*").compute(num1, num2));
Operation operate2 = OperationFactory.createOperate2("cn.jq.learn.simplefactorypattern.OperationDiv");
System.out.println(operate2.compute(num1, num2));
Operation operate3 = OperationFactory.createOperate3(OperationAdd.class);
System.out.println(operate3.compute(num1, num2));
}
}
—— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。