写在前面:设计模式不是干掉变化,而是让变化集中到一个区域,方便开发。
策略模式最大价值就是干掉了选择,特别是switch,通过这种模式,可以干掉在代码在switch中的强耦合关系。
按照惯例,还是来个生活写照:有一个国际的税务组织,需要和各国的税务规则打交道,每个国家都有自己的税务体系,需要根据实际的业务使用对应的税法规则。
用代码来模拟这个业务,一种简单的实现如下(把对应的国家信息传过去,根据这些信息来判断调用那个国家的税法规则):
enum COUNTRY {
CN_Tax,
FR_Tax,
US_Tax
}
public class StrategyTest {
public static void main(String[] args) {
TaxStrategy strategy = new TaxStrategy();
CalculateTax calculateTax = new CalculateTax();
strategy.setCalculateTax(calculateTax);
strategy.business(COUNTRY.CN_Tax);//中国税法
}
}
class TaxStrategy{
private CalculateTax calculateTax;
public void setCalculateTax(CalculateTax calculateTax) {
this.calculateTax = calculateTax;
}
//具体的业务
public void business(COUNTRY country) {
calculateTax.calculate(country);
}
}
class CalculateTax {
//根据具体的国家计算税收
public void calculate(COUNTRY country) {
switch (country) {
case CN_Tax:
System.out.println("中国税法");
break;
case FR_Tax:
System.out.println("法国税法");
break;
case US_Tax:
System.out.println("美国税法");
break;
default:
break;
}
}
}
代码本身很简单,这里来分析一下这种实现在设计上的问题,在上面的模拟中有两处变化,第一处是main函数中调用需要传递的国家信息来选择税法,第二处是根据国家判断对应的税法规则。第一处我们没法动,但是第二处可以优化。试想一下当需要增加一个国家时,就必须增加switch里面的case项,但是我们不希望改变里面的代码。那就可以采用派生的方式来解决。
public class StrategyTest {
public static void main(String[] args) {
TaxStrategy strategy = new TaxStrategy();
ICalculateTax calculateTax = new CNTax();
strategy.setCalculateTax(calculateTax);
strategy.business();
}
}
class TaxStrategy {
private ICalculateTax calculateTax;
public void setCalculateTax(ICalculateTax calculateTax) {
this.calculateTax = calculateTax;
}
//具体的业务
public void business() {
calculateTax.calculate();
}
}
//税收规则抽象接口
interface ICalculateTax {
void calculate();
}
//中国税收规则抽象接口实现
class CNTax implements ICalculateTax {
public void calculate() {
System.out.println("中国税法");
}
}
//美国税收规则抽象接口实现
class USTax implements ICalculateTax {
public void calculate() {
System.out.println("美国税法");
}
}
//法国税收规则抽象接口实现
class FRTax implements ICalculateTax {
public void calculate() {
System.out.println("法国税法");
}
}
通过派生的方式,来实现晚绑定,把第二处的变化都“赶”到ICalculateTax的实现类里面了,而且删除和增加都很方便,这也是策略模式的精华所在。