设计模式之工厂模式(简单工厂,工厂方法,抽象工厂)

设计模式6大原则:1 开闭原则:对拓展开放,对修改关闭2 单一职责原则:一个类只复杂一项职责3 里氏原则:子类可以扩展父类的功能,但不改变父类原有的功能4 依

设计模式6大原则:
1.开闭原则:对拓展开放,对修改关闭
2.单一职责原则:一个类只复杂一项职责
3.里氏原则:子类可以扩展父类的功能,但不改变父类原有的功能
4.依赖倒置原则:面向接口编程
5.接口隔离原则:设计接口功能尽量细粒度,最小功能单元
6.迪米特法则:降低耦合度(局部变量中,不要引入新的类)

 

这里对工厂模式做一个学习记录 

 

这里用简单计算器来举例。

很简单,我们需要3个输入:

a1 代表第一个数字

a2 代表第二数字

operator 代表运算符

这三个参数输入后得到一个输出result

 


 

1.平时的写法

/**
     * 这里简化了验证之类的逻辑
     * @param a1 第一个数字
     * @param a2 第二个数字
     * @param operator 运算符
     * @return
     */
    public static double calculate(double a1 , double a2 , String operator) {
        double result=0;
        switch (operator) {
        case "+":
            result=a1+a2;
            break;
        case "-":
            result=a1-a2;
            break;
        case "*":
            result=a1*a2;
            break;
        case "/":
            result=a1/a2;
            break;
            
        //TODO 也许还有别的这些运算符
        default:
            break;
        }
        return result;
    }
    //本身这样是没问题的而且也是非常简单的方式去实现计算的逻辑
    //如果逻辑简单这样写应该也是没问题的。问题是如果该程序非常复杂,这样的代码是很不好维护的。

2.简单工厂模式(Simple Factory)

用一个专业类(工厂类)来负责一种产品对象(计算方法)的创建。

1.我们将计算方法(+ - * / ...)提取出来单独作为一个类
2.再创建一个工厂类来负责每个计算方法的创建。

//计算方法
//将计算方式抽象成一个类
public abstract class CalculationRule {
    public abstract double getResult(double param1,double param2);
}
//简单的加法
public class AddRule extends CalculationRule {
    @Override
    public double getResult(double param1, double param2) {
        return param1+param2;
    }
}
//简单的减法
public class SubRule extends CalculationRule {
    @Override
    public double getResult(double param1, double param2) {
        return param1-param2;
    }
}

//简单工厂模式(Simple Factory)
public class CalculationRuleFactory {
    public static final String OPR_ADD="+"; //加法
    public static final String OPR_SUB="-"; //减法

    public static CalculationRule getCalculate(String operator) {
        CalculationRule cal=null;
        if (OPR_ADD.contentEquals(operator)) {
            cal=new AddRule();
        }else if(OPR_SUB.contentEquals(operator)) {
            cal=new SubRule();
        }
        return cal;
    }
}

//实际调用方式
public class MainEntry {
    public static void main(String[] args) {
        CalculationRule addRule=CalculationRuleFactory.getCalculate(CalculationRuleFactory.OPR_ADD);//获得加法算法;
        System.out.println(addRule.getResult(0.1,0.2));
    }
}

这种模式对于只有几种产品的管理来说是比较方便的,如果有很多产品(计算方法)的话,这种方式就不合时宜了。
然后我们会发现,简单工厂模式不符合:
1.单一职责原则:一个工厂负责了多个产品的创建
2.开闭原则:每次扩展算法时,需要修改已有代码


 

3.工厂方法模式(Factory Method)

对于简单工厂模式的问题:
1.将静态工厂打散,每一个算法对应一个算法工厂。
2.当拓展一个算法时候,对应拓展一个算法工厂。

/**
  * 工厂方法接口
 */
public interface CalculationRuleFactoryInterface {
    CalculationRule getRule();
}
/**
 * 加法工厂
 */
public class AddRuleFactory implements CalculationRuleFactoryInterface {
    @Override
    public CalculationRule getRule() {
        return new AddRule();
    }
}
/**
 * 减法工厂类
 */
public class SubRuleFactory implements CalculationRuleFactoryInterface {
    @Override
    public CalculationRule getRule() {
        return new SubRule();
    }

//调用
public static void main(String[] args) {
        //创建工厂
        CalculationRuleFactoryInterface factory=new SubRuleFactory();
        //请求算法并执行
        System.out.println(factory.getRule().getResult(0.2, 0.1));
    }

//另外一种方式
public class MainEntry {
    //Spring配置注入
    private CalculationRuleFactoryInterface calRulefactory;
    
    public void fire() {
        calRulefactory.getRule().getResult(0.2, 0.1);
    }
    //这样通过配置的方式想用什么算法就用什么算法
}

我们发现在工厂方法模式中:每一个工厂类只对应一个产品,即工厂和产品是一一对应的。
但是如果说我们需要一个工厂对应多个产品,那就需要用到抽象工厂模式了。


4.抽象工厂模式(Abstract Factory)

为了满足一对多的情况,这里我们假设我们还需要一个能够显示计算过程的产品

//我们添加一个抽象类
/**
 * 过程展示
 */
public abstract class ProcessView {
    public abstract void showView(double param1,double param2);
}
//加和减的过程展示都继承这个类
/**
 * 加法过程展示
 */
public class AddProcessView extends ProcessView {
    @Override
    public void showView(double param1, double param2) {
        System.out.println(""+param1+"+"+param2+"="+(param1+param2));
    }
}
/**
 * 减法过程展示
 */
public class SubProcessView extends ProcessView {
    @Override
    public void showView(double param1, double param2) {
        System.out.println(""+param1+"-"+param2+"="+(param1-param2));
    }
}


//我们将ProcessView统一交由CalculationRuleFactoryInterface管理
/**
  * 工厂方法接口
 */
public interface CalculationRuleFactoryInterface {
    CalculationRule getRule();
    ProcessView showProcess();//这个是新加的
}

//同时调整对应的工厂
/**
 * 加法工厂
 */
public class AddRuleFactory implements CalculationRuleFactoryInterface {
    @Override
    public CalculationRule getRule() {
        return new AddRule();
    }
    
    //下面是新加的
    @Override
    public ProcessView showProcess() {
        return new AddProcessView();
    }
}
/**
 * 减法工厂类
 */
public class SubRuleFactory implements CalculationRuleFactoryInterface {
    @Override
    public CalculationRule getRule() {
        return new SubRule();
    }
    
    //下面是新加的
    @Override
    public ProcessView showProcess() {
        return new SubProcessView();
    }
}

//最后尝试调用
public static void main(String[] args) {
        // 创建工厂
        CalculationRuleFactoryInterface factory = new SubRuleFactory();
        // 请求算法并执行
        System.out.println(factory.getRule().getResult(0.2, 0.1));
        // 请求显示过程
        factory.showProcess().showView(0.2, 0.1);
    }
显示:
0.1
0.2-0.1=0.1

  

这样来看似乎抽象工厂也没有满足单一职责原则和开闭原则
对于单一职责原则:明显抽象工厂不能满足。
对于开闭原则:在抽象工厂中,如果不增加工厂方法接口中的方法,仅添加产品类型,则是满足开闭原则的。反之不满足。
所以抽象工厂要求设计人员在设计之初就能够全面考虑,不会对现有结构出现删减情况,否则后期维护起来会有大麻烦。

 

题外:说起来工厂模式很多地方都有使用,我记得ifreecharts,Stimulsoft-reports,特别是apache大家族里面用得很多。本人是CURDBOY,工厂模式真的没怎么写过,哎罪过罪过。