1.介绍
1.1 定义
定义了一系列算法,分别封装起来,使他们之间可以互相替换,让算法可在不影响客户端的情况下发生变化。
简单说:准备一组算法,将每一个算法封装起来,让外部按照需要调用使得算法可以互换。
1.2 作用
• 减少了各种算法类与使用算法类之间的耦合(客户端方便根据不同的需要来解决不同的问题)
• 算法可独立于外部使用者而变化
2. 模式原理
2.1策略模式组成
组成(角色) | 关系 | 作用 |
抽象策略角色(Starategy) | 具体策略的父类(父接口) | 定义了所有策略公共接口 |
具体策略角色(Concrete Starategy) | 具体策略类 | 描述具体的策略行为 |
环境角色(Context) | 供外部使用者调用 | 用于连接上下文 |
2.2 使用步骤
• 创建抽象策略角色(Starategy),定义公共的策略接口
• 创建具体的策略角色(Concrete Starategy),实现各自不同的策略行为
• 创建环境角色(Context),用于连接上下文,供外部使用者调用
2.3 实例体现
案例概况:
2014年年底,北京市交通部门出台了公共交通出行收费新标准。其中公交车乘坐收费标准如下,十公里内收费一元,超过十公里之后每一元可乘坐公交车五公里;乘坐地铁收费标准如下:6公里内(含)收费3元,6-12(含)公里收费4元,12-22(含)公里收费5元,22-32(含)公里收费6元,32公里以上每多加一元可乘坐里程20公里。下面我们针对此项政策编写一个按照出行类型和出行里程来计算出行所需交付的价钱的程序。
步骤一:创建抽象策略类(接口),定义所有具体策略的公共接口(在此就是计算出行所需要的费用)
public interface CalculatorStarategy {
/**
* 按距离来计算价格
* @param km
* @return
*/
int calculatorPrice(int km);
}
步骤二:创建具体的策略类,实现计算乘坐不同交通工具所需要付的费用
public class BusStarategy implements CalculatorStarategy{
@Override
public int calculatorPrice(int busKm) {
//超过10公里的总距离
int exeraTotal = busKm - 10;
// 超过的距离是5公里的整数倍
int exeraFactor = exeraTotal / 5;
// 超过的距离对5公里取余
int fraction = exeraTotal % 5;
// 价格计算
int price = 1 + exeraFactor * 1;
return fraction > 0 ? ++price : price;
}
}
public class SubWayStarategy implements CalculatorStarategy{
@Override
public int calculatorPrice(int subWayKm) {
if (subWayKm <= 6) {
return 3;
} else if (subWayKm > 6 && subWayKm <= 12) {
return 4;
} else if (subWayKm > 12 && subWayKm <= 22) {
return 5;
} else if (subWayKm > 22 && subWayKm <= 32) {
return 6;
}
//在此,我们先按照其他距离只付7元来处理
return 7;
}
}
步骤三:创建一个环境角色(Context)这里使用TranficCalculator类代替,该类维护了一个抽象策略类(接口)的引用,并提供set()方法供其外部使用。代码如下:
public class TranficCalculator {
CalculatorStarategy calculatorStarategy;
//对外提供公共的setCalculatorStarategy方法
public void setCalculatorStarategy(CalculatorStarategy calculatorStarategy) {
this.calculatorStarategy = calculatorStarategy;
}
//在此调用了抽象类中计算价格的方法
public int calculatePrice(int km) {
return calculatorStarategy.calculatorPrice(km);
}
}
步骤四:最后由客户端调用,上面使用步骤中没有写出来,但是非常简单,一看便知。代码如下:
public class Test {
public static void main(String[] args) {
TranficCalculator calculator = new TranficCalculator();
calculator.setCalculatorStarategy(new SubWayStarategy());
int km = 16;
System.out.println("乘坐公交车" + km + "公里所需付的钱是::" + calculator.calculatePrice(km));
}
}
在此,改变
calculator.setCalculatorStarategy(new SubWayStarategy());
中不同的具体策略实例和km(乘坐公共交通工具的里程数)即可计算出乘坐不同交通工具所需要付的费用。
3. 策略模式的优缺点
3.1优点
• 策略类之间可以自由切换
由于所有具体策略类都实现了同一接口,所以它们之间可以自由切换
• 易于扩展
例如在此案例中,如果新加乘坐出租车的策略,只需要重新创建
一个出租车策略类即可,基本不需要修改原有的代码。
• 代码简洁,客户端避免使用多重条件判断语句(if else)
3.2 缺点
• 客户端必须知道所有的策略类,才能根据自身不同的需求决定使用哪一策略
• 策略模式将产生许多策略类,且,具体策略类中并不能完全避免条件语句的使用