策略模式的介绍
在软件开发中也常常遇到这样一种情况:实现某一功能可以有多种算法或者策略,我们根据实际情况选择不同的算法策略来完成该功能。例如:排序算法,可以使用插入排序,归并排序,冒泡排序等。
针对这种情况,一种常规的方法是将多种算法写在一个类中。例如,需要提供多种排序算法,可以将这些算法写到一个类中,每一个方法对应一个具体的排序算法;当然,也可以将这些排序算法封装在一个统一的方法中,通过if….else….或者case等条件语句来选择具体的算法。这两种实现方法我们称之为硬编码。然而。当很多算法集中在一个类中时,这个类就会变得臃肿,这个类的维护成本会变高,在维护时也更容易引发错误。如果需要增加一种新的排序算法,需要修改封装算法类的源代码。这就明显维护了我们上面所说的OCP原则和单一职责原则。
如果将这些算法或者策略抽象出来,提供一个统一的接口,不同的算法或者策略不同的实现类,这样在程序客户端就可以通过注入不同的实现对象来实现算法或者策略的动态替换,这种模式的可扩展性,可维护性也就更高,这就是我准备说的策略模式。
策略模式的定义
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
策略模式的使用场景
(1) 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时
(2) 需要安全地封装多种同一类型的操作时
(3) 出现同样抽象有多个子类,而有需要使用if-else或者switch-case来选择具体子类时。
策略模式的简单实现
下面我们以北京坐公共交通工具的费用计算来演示一个简单示例。在2014年12月28号之后,北京提高公交价格,不再是单一票价制,而是分段计价,也就是乘坐距离越远,价格越高。显然公交车和地铁的价格计算方式是不一样的,但是,我们的示例中需要计算乘不同出行工具的成本,下面我们就用策略模式进行代码演示
首先我们需要定义一个抽象的价格计算接口,这里命名为CaculateStrategy,具体代码如下:
/**
* 计算接口
* /
public interface CaculateStrategy{
/**
* 按距离计算价格
* @param km 公里
* @return 返回价格
int caculatePrice(int km);
}
对于每一种出行方式我们都有一个独立的计算策略类,这些策略都实现了CaculateStrategy接口,例如下面是公交车和地铁的计算策略类:
//公交车的价格计算策略
public class BusStrategy implements CaculateStrategy{
//北京公交车,十公里之内一元钱,超过十公里之后再加一元钱可以乘5公里
//@param Km 公里
// @return
@Override
public int CaculatePrice(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{
// 六公里内3元,6~12公里4元,12~22公里5元,22~32公里6元
// @param km 公里
//@return
@Override
public int caculatePrice(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;
}
//其他距离我们简化为7元钱
return 7;
}
}
我们创建一个扮演Context角色的类,这里将它命名为TranficCalculator,具体代码如下
//公交出行价格计算器
public class TranficCalculator{
public static void main(String[] args){
TranficCalculator calculator=new TranficCaculator();
// 设置计算策略
caculator.setStrategy(new BusStrategy()):
//计算价格
System.out.println("公交车乘16公里的价格:"+caculator.caculatePrice(16));
}
CalculateStrategy mStrategy;
public void setStrategy(CaculateStrategy mStrategy){
this.mStrategy=mStrategy;
}
public int caculatePrice(int km){
return mStrategy.caculatePrice(km);
}
}
分析
这种方案在隐藏实现的同时可扩展性变得更强,例如,当我们需要增加出租车的计算策略时,只需要添加一个出租车计算策略类,然后该策略设置给TranficCalculator,最好直接通过TranficCaculator对象的计算方法即可。
总结
策略模式通过建立抽象,将不同的策略构建成一个具体的策略实现,通过不同的策略实现算法替换。在简化逻辑,结构的同时,增强了系统的可读性,稳定性,可扩展性,这对于较为复杂的业务逻辑显得更为直观,扩展也更为方便。