说明
策略模式是一种行为型设计模式,可以根据不同的策略来进行不同的操作,我们常用的switch case和if else其实都可以认为是策略的体现,但缺点是想扩展新策略,就要去修改原来的业务代码,违背了面向对象的思想和原则,而策略模式可以很好的解决这个问题。
UML
策略模式的组成:
抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
具体策略角色:包装了相关的算法和行为。
环境角色:持有一个策略类的引用,最终给客户端调用。
代码
以一个简单的计数器为例,加减乘除是不同的四种策略,输入相同的数字,根据不同的策略可以获取不同的结果。代码如下。
抽象策略角色,计算策略的接口
/**
* @author ctl
* @date 2021/1/23
*/
public interface Counter {
int getResult(int[] nums);
}
具体策略角色,加法策略
/**
* @author ctl
* @date 2021/1/23
* 加法
*/
public class Addition implements Counter {
@Override
public int getResult(int[] nums) {
int r = 0;
for (int num : nums) {
r += num;
}
return r;
}
}
具体策略角色,减法策略
/**
* @author ctl
* @date 2021/1/23
* 减法
*/
public class Subtraction implements Counter {
@Override
public int getResult(int[] nums) {
int r = 0;
for (int i = 0; i < nums.length - 1; i++) {
r = nums[i] - nums[i + 1];
}
return r;
}
}
具体策略角色,乘法策略
/**
* @author ctl
* @date 2021/1/23
* 乘法
*/
public class Multiplication implements Counter {
@Override
public int getResult(int[] nums) {
int r = 0;
for (int i = 0; i < nums.length - 1; i++) {
r = nums[i] * nums[i + 1];
}
return r;
}
}
具体策略角色,除法策略
/**
* @author ctl
* @date 2021/1/23
* 除法
*/
public class Division implements Counter {
@Override
public int getResult(int[] nums) {
int r = 0;
for (int i = 0; i < nums.length - 1; i++) {
r = nums[i] / nums[i + 1];
}
return r;
}
}
环境角色,持有策略对象
/**
* @author ctl
* @date 2021/1/23
*/
public class CountHelper {
private Counter counter;
public void setCounter(Counter counter) {
this.counter = counter;
}
public int calculate(int[] nums) {
return counter.getResult(nums);
}
}
测试类
/**
* @author ctl
* @date 2021/1/23
*/
public class StrategyMain {
public static void main(String[] args) {
int calculate;
CountHelper countHelper = new CountHelper();
int[] nums = {8, 2};
System.out.println("开始计算" + Arrays.toString(nums));
// 加法
countHelper.setCounter(new Addition());
calculate = countHelper.calculate(nums);
System.out.println("加法:" + calculate);
// 减法
countHelper.setCounter(new Subtraction());
calculate = countHelper.calculate(nums);
System.out.println("减法:" + calculate);
// 乘法
countHelper.setCounter(new Multiplication());
calculate = countHelper.calculate(nums);
System.out.println("乘法:" + calculate);
// 除法
countHelper.setCounter(new Division());
calculate = countHelper.calculate(nums);
System.out.println("除法:" + calculate);
}
}
结果
可以看到分别计算出了8,2对应加减乘除的结果。
总结
应用场景:
1、 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
注意:
本例中的实现方式跟我之前写桥接模式中举例的实现方式有些类似,但千万不要搞混。
策略模式是一种行为型设计模式,是要根据不同的行为来采用不同的策略。
桥接模式是一种结构型设计模式,是为了达到抽象与实现解耦的目的,减少继承关系。
二者的本质和出发点及解决的问题是完全不同的,所以不要因为代码上有类似的地方而混淆了概念。
其实想写出优雅的代码,并不是心里想着要用哪种设计模式就行了,设计模式是为了让我们更好的去理解面向对象的思想,但千万不能墨守成规,为了设计而设计。
写代码是一个不断优化和重构的过程,在这个过程中,我们只要遵循了面向对象的编码规范,回过头来再看这些代码就会发现其实已经不自觉的用到了一些设计模式。
我认为真正的编码大神不是使用设计模式来写代码,而是他写的代码,成为了设计模式。