1 背景
看到一篇公账号文章https://mp.weixin.qq.com/s/ClesNl6doAPHTYXF8KQpGA,文章改标题很吸引人,主要内容是,在spring框架中实现了策略模式,但是,我个人认为文章中实际上是工厂模式,因此,回顾一下工厂模式和策略模式,并进行的比较。
工厂模式和策略模式的简单实践,都是以实现加减乘除等运算场景为目的,再通过“增加一个运算符号”这样的场景,来看看两种设计模式,在代码变动上的区别。
参考了文章https://blog.csdn.net/zwj_jyzl/article/details/80869905。
2 工厂模式和策略模式代码实现
首选定义一个接口,不同的符号计算类型只需要实现计算接口即可:
Calculate.java
package default_package.工厂模式和策略模式;
public interface Calculate {
public String geResult(int number1, int number2);
}
假设一开始只有加运算、减运算、乘运算这三种计算需求,因此,需要对计算接口分别实现这三种计算类:
Add.java
package default_package.工厂模式和策略模式;
public class Add implements Calculate {
@Override
public String geResult(int number1, int number2) {
return String.valueOf(number1 + number2);
}
}
Minus.java
package default_package.工厂模式和策略模式;
public class Minus implements Calculate {
@Override
public String geResult(int number1, int number2) {
return String.valueOf(number1 - number2);
}
}
乘法的实现类就不看了,大同小异。
2.1 简单工厂模式
既然是工厂模式,那肯定的要有一个工厂类,根据不同的输入,返回对应的类:
**CalculatorFactory.java **
package default_package.工厂模式和策略模式;
public class CalculatorFactory {
public static Calculate getCalculator(String opType) {
switch (opType) {
case "+":
return new Add();
case "-":
return new Minus();
case "*":
return new Multiple();
default:
return null;
}
}
}
我这里的返回的处理类每次都是new出来的,性能可能会稍微有点影响,但是没有线程安全问题;如果每个处理类都是实现new好放在map里面,如果存在共享数据,会存在线程安全问题,没有共享数据既不会有线程安全问题,比如我这里,每个处理类没有共享数据,new好好放进map,资源利用上更优;具体情况具体分析。
现在,通过工厂模式处理不同类型的运算:
调用
//需求,假设这里是动态变化的
int number1 = 1;
int number2 = 2;
String operationSymbol = "+";
//工厂模式示范
Calculate addOptype = CommonUtil.checkNullAndReturn(CalculatorFactory.getCalculator(operationSymbol), Main.class);
String result = addOptype.geResult(number1, number2);
System.out.println(number1 + operationSymbol + number2 + "=" + result);
经过分析,当需要增加新的计算符号时,需要对代码做三件事:
- 增加一个实现了“Calculate”接口的类,与工厂的输出类型保持一致
- 在工厂中增加相应的响应代码,返回那个新增的类的实例
- 不需要修改调用处的源码
2.2 策略模式
定义上下文类,用来接受不同的策略:
Context.java
package default_package.工厂模式和策略模式;
import java.util.PrimitiveIterator;
public class Context {
private Calculate calculate;
public Context(Calculate calculate) {
this.calculate = calculate;
}
public String getResult(int number1, int number2) {
return calculate.geResult(number1, number2);
}
}
通过策略模式进行调用:
//策略模式
Context context = new Context(new Add());//手动应用了计算策略,要应对不同的情况,此处需要switch或者if结构
result = context.getResult(number1, number2);
System.out.println(number1 + operationSymbol + number2 + "=" + result);
当需要增加新的计算符号时,需要对代码做两件事:
- 增加一个实现了“Calculate”接口的类
- 手动在调用处实现一个“应用计算策略”的情况
3 对比和总结
在代码层面进行对比,两者的共同点是,增加新的场景时,都需要额外新增实体类来应对增加的场景。
不同点在于两个方面,使用策略模式时,调用者/方法使用者,自己需要知道哪种策略对应了哪种情况,自己要在方法调用处实现选择结构或者判断结构,实现不同的策略应用;如果多处调用,则需要在多处实现的一堆策略选择代码;
使用工厂模式时,调用者/方法使用者只需要传入某种标记场景的参数,然后使用工厂给出的类即可,到处调用也不需要调用者实现多余的代码的,因为实现过程都已经放到工厂中了。
个人见解,肯定有不对的地方,请指正。