背景
策略模式(Strategy模式)是行为模式之一,它对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法(策略)选择交由客户端决定。Strategy模式主要用来平滑地处理算法的切换 。
策略模式的UML类图如下,主要的类有三个:
1.抽象策略类Strategy,定义所有支持的算法的公共接口;
2.具体策略类StrategyA,StrategyB,封装具体的算法;
3.上下文Constext类,根据策略类的配置,通过多态实现不同算法的调用
下面例子以计算0到某个正整数的和SumUntil两种算法来体现策略模式:
class SumUntilStrategy
{
public:
virtual ~SumUntilStrategy() {};
virtual size_t calSumUntilPara(size_t para) = 0;
};
class SumUntilStrategyNormal : public SumUntilStrategy
{
public:
size_t calSumUntilPara(size_t para) override {
size_t sum = 0;
for (size_t i = 0; i < para + 1; i++) {
sum += i;
}
return sum;
}
};
class SumUntilStrategyFast : public SumUntilStrategy
{
public:
size_t calSumUntilPara(size_t para) override {
return (0 + para) * (para + 1)/2;
}
};
class SumUntilContext
{
public:
SumUntilContext(SumUntilStrategy* sumUntil);
~SumUntilContext();
size_t sumUntilRet(size_t para);
private:
SumUntilStrategy* _sumUntil;
};
SumUntilContext::SumUntilContext(SumUntilStrategy * sumUntil)
: _sumUntil(sumUntil)
{
}
SumUntilContext::~SumUntilContext()
{
if (_sumUntil) {
delete _sumUntil;
_sumUntil = NULL;
}
}
size_t SumUntilContext::sumUntilRet(size_t para)
{
if (_sumUntil) {
return _sumUntil->calSumUntilPara(para);
}
return -1;
}
int main()
{
// 笨算法累加
SumUntilContext *sumUntil = new SumUntilContext(new SumUntilStrategyNormal());
size_t ret = sumUntil->sumUntilRet(100);
delete sumUntil;
sumUntil = NULL;
// 类似梯形面积计算的简化算法
sumUntil = new SumUntilContext(new SumUntilStrategyFast());
ret = sumUntil->sumUntilRet(99);
delete sumUntil;
sumUntil = NULL;
return 0;
}
写完后发现,用这种策略模式客户端还是需要认识两种不同的策略类名SumUntilStrategyNormal和SumUntilStrategyFast,能不能让客户端不感知这些呢?可以设定两个枚举,修改SumUntilContext的构造函数,不再传入SumUntilStrategy指针,而是在构造函数中通过传入的枚举来决定如何初始化_sumUntil成员,代码如下(只展示了修改的函数,其他和上面的示例代码保持一致):
enum SumUntilWays
{
SUM_UNTIL_NORMAL,
SUM_UNTIL_FAST
};
class SumUntilContext
{
public:
SumUntilContext(SumUntilWays way); // 构造函数不再传入指针而是枚举
~SumUntilContext();
size_t sumUntilRet(size_t para);
private:
SumUntilStrategy* _sumUntil;
};
SumUntilContext::SumUntilContext(SumUntilWays way)
{
switch (way) {
case SUM_UNTIL_NORMAL:
_sumUntil = new SumUntilStrategyNormal();
break;
case SUM_UNTIL_FAST:
_sumUntil = new SumUntilStrategyFast();
break;
default:
_sumUntil = NULL;
break;
}
}
int main()
{
// 客户端只需要认识SumUntilContext类和要使用的方法枚举SumUntilWays即可
SumUntilContext *sumUntil = new SumUntilContext(SUM_UNTIL_NORMAL);
size_t ret = sumUntil->sumUntilRet(100);
delete sumUntil;
sumUntil = NULL;
sumUntil = new SumUntilContext(SUM_UNTIL_FAST);
ret = sumUntil->sumUntilRet(99);
delete sumUntil;
sumUntil = NULL;
return 0;
}