简单工厂搭配策略模式
简单介绍一下这两个设计模式。
策略模式的思想就是,当你要根据特定场景使用特定算法时,可以把用一个接口提供这个算法,不同的场景对他进行不同的实现。主流程通过不同的实现类
来完成这个功能。
简单工厂就是根据一个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。