简单工厂模式(Simple Factory Pattern)

112 阅读6分钟

简单工厂模式

动机

为什么会有简单工厂这个模式的呢?这概念是怎么引入的呢?没有简单工厂之前是如何开发的?遇到的主要问题是什么?

我们来考虑一个简单的软件应用场景,一个计算器系统可以提供多个运算(如加、减、乘、除等), 这些运算功能都源自同一个类,不过在继承基类后不同的子类修改了部分属性从而使得它们可以呈现不同的运算,如果我们希望在使用这些运算时,不需要知道这些具体运算类的名字,只需要知道表示该运算类的一个参数,并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的运算对象,此时,就可以使用简单工厂模式。

概述

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。

在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

学习思路

  1. 追根溯源:
  2. 门卫思想:是什么? 为什么? 怎么用?

代码实现

一、未使用简单工厂模式

运算类代码

public class Operation {
    /**
     * 运算逻辑
     * @param numberA  运算数字A
     * @param numberB  运算数字B
     * @param operator 运算符
     * @return
     * @throws Exception
     */
    public static double GetResult(double numberA,double numberB,String operator) throws Exception {
            double result = 0d;
            switch (operator){
                case"+":
                    result =numberA+numberB;
                    break;
                case"-":
                    result=numberA-numberB;
                    break;
                case"*":
                    result=numberA*numberB;
                    break;
                case"/":
                    if(numberB==0){
                        throw new Exception("除数不能为0!");
                    }
                    result=numberA/numberB;
                    break;
            }
        return result;
    }
}

客户端代码

 public static void main(String[] args) {
        try{
            double NumberA = 10;
            double NumberB = 5;
            String operate = "/";
            double Result = 0;
            Result = Operation.GetResult(NumberA,NumberB,operate);
            System.out.println(Result);
        } catch (Exception e) {
            System.out.println("您的输入有误:"+e.getMessage());
        }
    }

这里我们可以发现,逻辑代码是堆在一起的,简单业务实现起来还无法发现问题,但是如果需要扩展新的业务时,该如何进行修改呢?那就需要修改运算类,并且可能会影响到其他业务的逻辑运算。
下面我们来看一下使用简单工厂模式后的代码

二、使用简单工厂模式

具体运算实现类代码

/**
 * 加法运算类,继承运算类
 */
public class OperationAdd  extends Operation {

    @Override
    public Double getResult() throws Exception {
        return getNumberA()+getNumberB();
    }
}
/**
 * 减法运算类,继承运算类
 */
public class OperationSub extends Operation {
    @Override
    public Double getResult() throws Exception {
        return getNumberA()- getNumberB();
    }
}
/**
 * 乘法运算类,继承运算类
 */
public class OperationMul extends Operation {
    @Override
    public Double getResult() throws Exception {
        return getNumberA()*getNumberB();
    }
}
/**
 * 除法运算类,继承运算类
 */
public class OperationDiv extends Operation {
    @Override
    public Double getResult() throws Exception {
        if (getNumberB()==0) {
            throw new ArithmeticException("除数不能为'0'!");
        }
        return getNumberA()/getNumberB();
    }
}

抽象运算类

/**
 * 抽象运算类
 */
public abstract class Operation {
    private double numberA;
    private double numberB;

    public double getNumberA() {
        return numberA;
    }
    public void setNumberA(double numberA) {
        this.numberA = numberA;
    }
    public double getNumberB() {
        return numberB;
    }
    public void setNumberB(double numberB) {
        this.numberB = numberB;
    }

    public  abstract Double getResult() throws Exception;
}

运算工厂类

/**
 * 运算工厂类
 */
public class OperationFactory {
    public static Operation oper = null;

    public static Operation createOperation(String operator){
        switch (operator){
            case"+":
                oper = new OperationAdd();
                break;
            case"-":
                oper = new OperationSub();
                break;
            case"*":
                oper = new OperationMul();
                break;
            case"/":
                oper = new OperationDiv();
                break;
        }
        return oper;
    }

}

客户端代码

/**
 * 客户端代码
 */
public class Main {

    public static void main(String[] args) throws Exception{
        //加法
        Addpend(10,4);
        //减法
        Subtract(-2,5);
        //乘法
        Multiply(3,25);
        //除法
        Divide(1,20);
    }
    public static void Addpend(double numberA,double numberB) throws Exception {
        String add = "+";
        Operation Add = OperationFactory.createOperation(add);
        Add.setNumberA(numberA);
        Add.setNumberB(numberB);
        Double result = Add.getResult();
        System.out.println("加法:"+result);
    }

    public static void Subtract(double numberA,double numberB) throws Exception {
        String sub = "-";
        Operation Sub = OperationFactory.createOperation(sub);
        Sub.setNumberA(numberA);
        Sub.setNumberB(numberB);
        Double result = Sub.getResult();
        System.out.println("减法:"+result);
    }

    public static void Multiply(double numberA,double numberB) throws Exception {
        String mul = "*";
        Operation Mul = OperationFactory.createOperation(mul);
        Mul.setNumberA(numberA);
        Mul.setNumberB(numberB);
        Double result = Mul.getResult();
        System.out.println("乘法:"+result);
    }

    public static void Divide(double numberA,double numberB) throws Exception {
        String div = "/";
        Operation Div = OperationFactory.createOperation(div);
        Div.setNumberA(numberA);
        Div.setNumberB(numberB);
        Double result = Div.getResult();
        System.out.println("除法:"+result);
    }

}

模式分析

将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。

在调用工厂类的工厂方法时,由于工厂方法是静态方法,使用起来很方便,可通过类名直接调用,而且只需要传入一个简单的参数即可,在实际开发中,还可以在调用时将所传入的参数保存在XML等格式的配置文件中,修改参数时无须修改任何源代码

简单工厂模式最大的问题在于工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背的。

简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节

结构图

在这里插入图片描述

结构分析

Factory:工厂角色
工厂角色负责实现创建所有实例的内部逻辑

Product:抽象产品角色
抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口

ConcreteProduct:具体产品角色
具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

使用场景

  1. 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  2. 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。

总结

  1. 创建型模式对类的实例化过程进行了抽象,能够将对象的创建与对象的使用过程分离。
  2. 简单工厂模式又称为静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
  3. 简单工厂模式包含三个角色:工厂角色负责实现创建所有实例的内部逻辑;抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口;具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
  4. 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
  5. 简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。
  6. 简单工厂模式适用情况包括:工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。