策略模式:定义了算法家族,分别封装起来。让他们之间可以相互替换。
从概念上看,所有的算法完成的都是相同的工作,只是实现不同,他可以以相同的方式调用所有的算法。减少了各种算法与使用算法类之间的耦合。
因此,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
以下代码主要是封装了加减乘除四种算法。
public class Operation {
public double getResult(double numA, double numB) throws Exception {
return 0d;
}
}
class OperationAdd extends Operation {
public double getResult(double numA, double numB) {
return numA + numB;
}
}
class OperationSub extends Operation {
public double getResult(double numA, double numB) {
return numA - numB;
}
}
class OperationMul extends Operation {
public double getResult(double numA, double numB) {
return numA * numB;
}
}
class OperationDiv extends Operation {
public double getResult(double numA, double numB) throws Exception {
if (0d == numB) {
throw new Exception("除数不能为0");
} else {
return numA / numB;
}
}
}
当定义好程序中的算法家族后。在StrategyContext中定义Operation属性。而后增加方法getResult
间接调用算法。从而得到结果。StrategyContext
类代码如下:
public class StrategyContext {
private Operation operation;
//结合了简单工厂模式
public StrategyContext(String operator) throws Exception {
switch (operator) {
case "+":
this.operation = new OperationAdd();
break;
case "-":
this.operation = new OperationSub();
break;
case "*":
this.operation = new OperationMul();
break;
case "/":
this.operation = new OperationDiv();
break;
default:
throw new Exception("运算符错误");
}
}
//当然,也可以这个样子
public StrategyContext(Operation operation) {
this.operation = operation;
}
public double getResult(double numA, double numB) throws Exception {
return operation.getResult(numA, numB);
}
}
这样做法后,当客户端代码需要获取某一种类算法时。只需要将operator传入构造中。而后调用StrategyContext的getResult方法,便可得到正确结果。
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
try {
System.out.println("输入第一个数字A");
double numA = sc.nextDouble();
System.out.println("输入运算符:+、-、*、/");
String operator = sc.next();
System.out.println("输入第二个数字B");
double numB = sc.nextDouble();
StrategyContext context = new StrategyContext(operator);//策略模式
double result = context.getResult(numA, numB);
System.out.println(String.format("结果是:%s", result));
} catch (Exception e) {
throw e;
} finally {
sc.close();
}
}
那么策略模式主要解决了什么问题呢?
- 减少了多余了判断。试想,当所有的算法情况,全部写在同一个文件中。通过大量的if-else或case来选择执行方式,那么这段程式的复杂度将会非常之高,可维护性也非常差。
- 此外,还可以简化单元测试。因为采取策略模式后,每个算法都有一个属于自己的类。可以单独测试。
回想一下上一篇的"简单工厂模式",似乎也是做类似的事情。那么两者的区别在哪呢?我们看一下两者区别:
//简单工厂模式的使用
Operation operation = OperationFactory.getOperation(operator);
double result = operation.getResult(numA, numB);
//策略模式的使用方式
StrategyContext context = new StrategyContext(operator);
double result = context.getResult(numA, numB);
可以看到,简单工厂模式中,需要认识工厂类,以及算法类的基类,通过基类调用getResult方法得到结果。
而策略模式中,只需要知道StrategyContext类,就可以得到结果。
这使得具体的算法与客户端代码分离,甚至连算法类的基类是谁都可以不知道。反正我只需要调用StrategyContext的getResult方法。耦合性更低。
其次,简单工厂模式,是创建型模式。是负责资源分发。
而策略模式则是行为型模式。两者本质是不同的。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。