策略模式
概念
定义一系列算法,并将每一个算法封装起来,而且使它们可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
使用场景
1)针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
2)需要安全地封装多种同一类型的操作时。
3)出现同一抽象类有多个子类,而又需要使用if-else或者swich-case来选择具体子类时。
案例:交通计费
没有使用策略时:
public class PriceCalculator {
private static final int BUS=1;
private static final int SUBWAY=2;
public static void main(String[] args) {
PriceCalculator calculator = new PriceCalculator();
System.out.println("坐15公里的公交车票价为:"+calculator.calculatePrice(15,BUS));
System.out.println("坐15公里的地铁票价为:"+calculator.calculatePrice(15,SUBWAY));
}
//公交车计费,十公里之内一元钱,之外每加一元钱可以乘5公里
private int busPrice(int km){
//超过10公里的总距离
int extraTotal=km-10;
//超过的距离是5的公里倍数
int extraFactor=extraTotal /5;
//超过的距离对5公里取余
int fraction=extraTotal % 5;
//价格计算
int price=1+extraFactor*1;
return fraction>0?++price:price;
}
//地铁计费 6公里内 3元 6<=km<=12公里 4元 12<=km<=22公里 5元 22<=km<=32公里 6元
private int subwayPrice(int km){
if(km<=6){
return 3;
}else if(km>6 && km<12){
return 4;
}else if(km>12 && km <22){
return 5;
}else if(km>22 && km<32){
return 6;
}
return 7;
}
int calculatePrice(int km,int type){
if(type==BUS){
return busPrice(km);
}else if(type==SUBWAY){
return subwayPrice(km);
}
return 0;
}
}
分析:PriceCalculator类中的代码很明显的问题是没有使用单一职责,如果再多增加一些类别的交通工具计费,比如增加一个taxi计费,就得修改calculatePrice方法中的代码,增加一个分支判断,那么这个类中的代码逐渐会变得非常臃肿,且不好维护。
使用策略模式重构后
public interface CalculateStrategy {
//按距离来计算价格
int calculatePrice(int km);
}
public class BusStrategy implements CalculateStrategy {
//公交车计费,十公里之内一元钱,之外每加一元钱可以乘5公里
@Override
public int calculatePrice(int km) {
//超过10公里的总距离
int extraTotal=km-10;
//超过的距离是5的公里倍数
int extraFactor=extraTotal /5;
//超过的距离对5公里取余
int fraction=extraTotal % 5;
//价格计算
int price=1+extraFactor*1;
return fraction>0?++price:price;
}
}
public class SubwayStrategy implements CalculateStrategy{
//地铁计费 6公里内 3元 6<=km<=12公里 4元 12<=km<=22公里 5元 22<=km<=32公里 6元
@Override
public int calculatePrice(int km) {
if(km<=6){
return 3;
}else if(km>6 && km<12){
return 4;
}else if(km>12 && km <22){
return 5;
}else if(km>22 && km<32){
return 6;
}
return 7;
}
}
public class TranficCalculator {
public static void main(String[] args) {
TranficCalculator calculator = new TranficCalculator();
//设置计算策略
calculator.setmStrategy(new BusStrategy());
//计算价格
System.out.println("公交车乘15公里的价格:"+calculator.calculatePrice(15));
}
//这一部分代码可以单独放在一个类中
CalculateStrategy mStrategy;
//使用set方法注入依赖
public void setmStrategy(CalculateStrategy mStrategy) {
this.mStrategy = mStrategy;
}
public int calculatePrice(int km){
return mStrategy.calculatePrice(km);
}
}
结果:
公交车乘15公里的价格:2
假如需要添加出租车方式的计费,只需要添加一个出租车计算策略类,然后在TranficCalculator中set进去如下:
public class TaixStrategy implements CalculateStrategy{
//价格 公里*3
@Override
public int calculatePrice(int km) {
return km*3;
}
}
TranficCalculator calculator = new TranficCalculator();
//设置计算策略
calculator.setmStrategy(new TaixStrategy ());
分析:这种方式通过建立抽象,将不同的策略构建成一个具体的策略实现,通过不同的策略实现算法的替换,简化了逻辑,结构,还增强了可读性,稳定性,扩展性。
策略模式优缺点
优点:1) 算法可以自由替换 2) 避免使用多重条件判断 3) 扩展性良好。
缺点:1) 策略类数量增多 2)所有的策略类都需要对外暴露