原则
分离变化部分,封装接口,基于接口编程各种功能。此模式让行为的变化独立于算法的使用者。
策略模式的优点
- 提供了快速替换继承关系的办法
- 减少代码中的if else 等判断语句
- 实现的选择:策略模式可以提供不同的实现。
策略模式的缺点 - 策略模式会造成很多策略类
- 通讯开销很大
- 必须自行知道所有的实现类有何不同?
因此只有当行为类和角色行为相关的时候才需要使用策略模式。
策略模式所用到的三个设计原则 - 封装变化。供动态改变调用。
- 针对接口,超类编程,不针对实现编程。
- 多用组合,少用继承。组合最大的好处就是具有弹性,给代码维护和需求修改提供极大的便利。
例
有一场演讲比赛,有十个评委对参赛选手的成绩进行打分,但最终要通过评委的平均分来决定选手的名次。现在有两种求平均分的策略:
第一种:将十名裁判的分加起来求平均值。
第二种:去掉最高分和最低分后求平均值。
策略模式结构中包含了三种角色:1.策略 2.上下文 3.具体策略
策略:策略是一个接口,该接口定义若干算法标识,即定义了若干个抽象方法。
上下文(context):上下文是依赖接口的类(是面向策略二设计的类),即上下文中包含了策略变量。上下文中提供一个方法,该方法委托策略变量调用具体策略所实现的策略接口中的方法。
具体策略:具体策略是实现策略接口的类。具体策略实现策略接口所定义的抽象方法。
代码
/**
* 策略接口
* @author lu
* @since 1.0, 2020年6月22日
*/
public interface Strategy {
public double getAverge(double a[]);
}
/**
* 策略A:直接求平均分
* @author lu
* @since 1.0, 2020年6月22日
*/
public class StrategyA implements Strategy{
@Override
public double getAverge(double[] a) {
double score = 0,sum = 0;
for (int i = 0; i < a.length; i++) {
sum = sum + a[i];
}
score = sum/a.length;
return score;
}
}
/**
* 策略B:去掉最高分和最低分后求平均分
* @author lu
* @since 1.0, 2020年6月22日
*/
public class StrategyB implements Strategy{
@Override
public double getAverge(double[] a) {
double score = 0,sum = 0;
Arrays.sort(a);
for (int i = 1; i < a.length-1; i++) {
sum = sum+a[i];
}
score = sum/(a.length-2);
return score;
}
}
/**
* 策略上下文
* @author lu
* @since 1.0, 2020年6月22日
*/
public class StrategyContext {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
/**
* 构造函数
* @param strategy
*/
public StrategyContext(Strategy strategy) {
super();
this.strategy = strategy;
}
public double getAverge(double a[]){
if(strategy != null){
double averge = strategy.getAverge(a);
return averge;
}else{
System.out.println("没有求平均值的策略");
return -1;
}
}
}
/**
* 测试客户端
* @author lu
* @since 1.0, 2020年6月22日
*/
public class Client {
public static void main(String[] args) {
//打分
double a[] = {1,6,2,5,3,9,7,8,6,5};
//1、创建具体打分策略
StrategyA strategyA = new StrategyA();
//2、创建策略上下文时将具体的策略实现对象注入到上下文中
StrategyContext strategyContext = new StrategyContext(strategyA);
//3、完成具体的策略实现的调用
double averge = strategyContext.getAverge(a);
System.out.println("策略A平均分:"+averge);
//=====第二种策略=====
StrategyB strategyB = new StrategyB();
strategyContext.setStrategy(strategyB);
averge =strategyContext.getAverge(a);
System.out.println("策略B平均分:"+averge);
}
}