Strategy(策略模式)
定义一系列算法,把他们一个个封装起来,并且是他们可以互相替换(变化)。该模式似的算法可以独立于使用它的客户程序(稳定的)而变化(扩展,子类)
动机(Motivation)
在软件构建的过程中,某些对象使用的算法可能是多种多样的,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一种性能负担
原先
比如现在需要有一个税种的计算系统,其中支持计算各国的税种,那么他的代码描述就是如下:
当我们需要增加一个新的税务种类时、我们不但需要修改TaxBase中的参数,还需要在SalseOrder中添加关于新增加税种的一个判断,然后才能进行相应的计算。违反了开闭原则,同时也违反了依赖倒置原则。
// 税务种类枚举
enum TaxBase {
CN_Tax,
US_Tax,
DE_Tax,
};
class SalesOrder{
TaxBase tax;
public double CalculateTax() {
//根据不同的税务种类进行操作
if (tax == TaxBase.CN_Tax){
//CN***********
}
else if (tax == TaxBase.US_Tax){
//US***********
}
else if (tax == TaxBase.DE_Tax){
//DE***********
}
//....
return 0;
}
};
重构
// 操作税务的上下文信息
class Context {
}
// 税务种类枚举
enum TaxBase {
CN_Tax,
US_Tax,
DE_Tax,
};
// 将创建哪个税务接口封装到工厂中、由工厂创建、将变化点封装起来了
class strategyFactory {
public TaxStrategy NewStrategy(TaxBase taxBase) {
switch (taxBase) {
case CN_Tax:
return new CNTax();
case US_Tax:
return new USTax();
case DE_Tax:
return new DETax();
}
return null;
}
}
// 定义一个操作税务的接口类
interface TaxStrategy {
double Calculate(Context context);
}
// 各国税务实现接口即可
class CNTax implements TaxStrategy {
@Override
public double Calculate(Context context) {
return 0;
}
}
class USTax implements TaxStrategy {
@Override
public double Calculate(Context context) {
return 0;
}
}
class DETax implements TaxStrategy {
@Override
public double Calculate(Context context) {
return 0;
}
}
class SalesOrder{
TaxStrategy taxStrategy;
SalesOrder(strategyFactory strategyFactory) {
// 通过工厂创建税务实现类
taxStrategy = strategyFactory.NewStrategy(TaxBase.CN_Tax);
}
public double CalculateTax() {
// 税务操作的上下文相关信息
Context context = new Context();
double calculate = taxStrategy.Calculate(context);
return calculate;
}
};
对比原先代码SalesOrder的CalculateTax函数来说,他多态调用了TaxStrategy类中的Calucate方法。而TaxStrategy来说他的每个子类都是一种新的税种计算方式,每个税种计算中还实现了自己对应的税种计算的方法。
在扩展的时候,需要增加TaxStrategy的子类就行了,不需要在改变SalesOrder的中的代码了
而且创建税务实现类也封装到工厂中、由工厂选择性的创建需要的类、进一步封装了变化点
要点总结
Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便的根据需要在各个算法之间进行切换
Strategy模式提供了用条件判断语句的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。尤其是条件判断语句在未来会有增加可能性的时候,应该优先考虑Strategy模式。