简单工厂搭配策略模式

简单介绍一下这两个设计模式。

策略模式的思想就是,当你要根据特定场景使用特定算法时,可以把用一个接口提供这个算法,不同的场景对他进行不同的实现。主流程通过不同的实现类

来完成这个功能。

简单工厂就是根据一个type返回对应的对象。

简单工厂+策略模式就可以实现根据调用方传过来的type通过简单工厂获取到对数据操作的实现类,然后操作数据返回,当新增一个type时,可以很清晰解决,避免误改。

下面以一个计算器举例,其实这不是一个很好的例子。

public class CalculatorTest {
    /**
     * 调用方
     */
    @Test
    public void test() {
        double num1 = 1.1;
        double num2 = 2.0;
        double result = calculate(num1, num2, CaculatorType.ADD);
        System.out.println(result);
    }

    /**
     * 接收方
     * @param type 计算方法类型,是一个枚举值
     * @return 计算结果
     */
    public double calculate(double num1, double num2, CaculatorType type) {
        CalculatorFactory calculatorFactory = new CalculatorFactory();
     //根据type获取计算器 Calculator calculator
= calculatorFactory.getCalculator(type); return calculator.caculate(num1, num2); } }

 这样做的好处就是未来新曾别的计算方法时,例如减法。思路很清晰,增加一个枚举值,增加一个减法的算法,

calculate 这个方法完全不需要动,在实际的开发过程中,我们应该尽量保证主流程不被修改,这样才会减少Bug,故障的发生。
下面看一下这个工厂类。
public class CalculatorFactory {
    private EnumMap<CaculatorType,Calculator> typeToCalculator = Maps.newEnumMap(CaculatorType.class);

    {
        //当方法容易实现时,可以用lambda表达式实现策略模式从而避免每次都要新建一个类
        typeToCalculator.put(CaculatorType.ADD, (num1, num2) -> num1 + num2);
        typeToCalculator.put(CaculatorType.SUB, (num1, num2) -> num1 - num2);
        typeToCalculator.put(CaculatorType.MUL, (num1, num2) -> num1 * num2);
        typeToCalculator.put(CaculatorType.DIV, (num1, num2) -> num1 / num2);
    }
    public  Calculator getCalculator(CaculatorType type){
        return typeToCalculator.get(type);
    }
}

常见的工厂类可能会用switch,但是个人感觉用map的形式更好,首先时间复杂度为O(1)当然,实现类的数量不可能太多,性能提升不会很明显。

但是可读性会高,根据类型去容器里取对象,新增或删除时,加一行或者删一行代码即可,还有两点可能与其他看过的版本不同。

1.使用了java8支持的lambda表达式代替了实现类,如果代码较短,不必新增一个类,用lambda表达式比较方便。

2.我这里用的map是EnumMap,当然也可以用TreeMap和HashMap也可以,用EnumMap的原因是EnumMap底层会创建一个与CaculatorType实例

个数相等的数组来存储。如果是hashmap会创建一个2的n次方的数组,浪费空间,并且hashmap还需要hash寻找数据存放位置,并且有可能hash冲突。

使用TreeMap的话插入和查找的时间复杂度是O(logn)。而EnumMap的最大时间复杂度就是O(1),因为EnumMap底层创建一个和它元素数

一样大的数组,当put时,如果put的是CaculatorType.ADD,会将它放入底层数组索引为CaculatorType.ADD.ordinal()的位置,也就是0,ordinal()

代表第几个实例,取得时候也是取索引为0的对象,不通过任何计算,直接从数组拿,所以如果想用map可以考虑一下key适不适合用枚举,如果

适合用枚举,果断采用并且用EnumMap。