设计模式之策略模式
2016-11-05 23:07
162 查看
设计模式之策略模式
1. 问题引入
案例描述:
对于不同职位的员工,年终奖的计算方式不尽相同,并且职位的类别在可见的未来还会增加。试设计一个合适的年终奖计算方式,来适应这一情况。问题抽象:
在某个问题中,针对不同的情况,会有不同的算法。而且,解决该问题的算法,未来很有可能会改变。不同的时候需要不同的算法,并且我们不想支持我们并不使用的算法。 ——— 《设计模式,GOF》
2.解决方案
方案一:分情况考虑问题。
枚举职位,针对不同的职位选择不同的年终奖计算方案。代码如下:
#include <iostream> using namespace std; typedef float Bonus; //年终奖的金额 class Context{}; //计算年终奖需要的上下文条件 //枚举职位 enum Position { CEO, // 首席执行官 PROGRAMMER, // 程序猿 PM, // 产品经理 ACCOUNTANT // 会计 }; Bonus CEOBonus(const Context& context) { Bonus bonus = 0.0; cout << "CEO的年终奖计算方式." << endl; //... return bonus; } Bonus ProgrammerBonus(const Context& context) { Bonus bonus = 0.0; cout << "程序猿的年终奖计算方式." << endl; //... return bonus; } Bonus PMBonus(const Context& context) { Bonus bonus = 0.0; cout << "PM的年终奖计算方式." << endl; //... return bonus; } Bonus AccountantBonus(const Context& context) { Bonus bonus = 0.0; cout << "会计的年终奖计算方式." << endl; //... return bonus; } //年终奖的计算策略 class BonusStategy { private: Position m_pos; //职位 public: BonusStategy(Position pos) : m_pos(pos) {} //改变职位 void changePos(Position pos) { m_pos = pos; } //获取当前职位 Position position() const { return m_pos; } Bonus CalBonus() const { Bonus bonus = 0.0; Context context; //Context的处理... switch (m_pos) { case CEO: bonus = CEOBonus(context); break; case PROGRAMMER: bonus = ProgrammerBonus(context); break; case PM: bonus = PMBonus(context); break; case ACCOUNTANT: bonus = AccountantBonus(context); break; } return bonus; } }; int main() { BonusStategy bs(Position::PROGRAMMER); Bonus bonus = bs.CalBonus(); return 0; }
当职位种类数不变的情况下,这样的解决方案比较完美地解决了这个问题。其一是,我们可以将年终奖计算的函数放在一个文件下,将
BonusStategy类放在另一个文件。当我们需要改变某个职位的年终奖计算方式时,只需修改计算函数,而不会影响
BonusStategy类。 其二是,当我们需要改变一个人的职位时,只需要改变他的
Position变量,不必考虑其他因素。 另外,这个方法比较通俗易懂,不涉及特别复杂的编程技巧,可读写较强。
但是,这个方案也有两点弊端。其一是,冗余代码过多。实际上每个
BonusStategy对象在
CalBonus()函数中,只会选择一个分支,而它却存储了其他不需要的分支,更加耗费CPU。其二是,随着公司的规模不断扩大,不断有新的职位产生。当增加新的职位时,我们不仅需要增加其对应的枚举类型字段和年终奖计算函数,而且需要在
BonusStategy::CalBonus()中的
switch语句增加对应的
case语句。
如,当我们需要新增一个架构师(Architecte)时。我们需要先在
Position类型中增加
ARCHITESTE字段,然后,增加计算其年终奖的
Bonus ArchitecteBonus(const Context& context)函数,最后需要在在
BonusStategy::CalBonus()函数的
switch语句中加入下列语句 :
case ARCHITESTE: bonus = ArchitecteBonus(context); break;
方案二: 策略模式(Strategy)所提供的解决方案
将算法封装起来,并提供相同的接口,针对不同的职位,提供不同的算法实现。代码实现如下:
#include <iostream> using namespace std; typedef float Bonus; //年终奖的金额 class Context {}; //计算年终奖需要的上下文条件 class BonusStategy { public: virtual Bonus CalBonus (const Context& context) const = 0; }; class CEOBonus : public BonusStategy { public: virtual Bonus CalBonus (const Context& context) const { Bonus bonus = 0.0; cout << "CEO的年终奖计算方式." << endl; //... return bonus; } }; class ProgrammerBonus : public BonusStategy { public: virtual Bonus CalBonus (const Context& context) const { Bonus bonus = 0.0; cout << "程序猿的年终奖计算方式." << endl; //... return bonus; } }; class PMBonus : public BonusStategy { public: virtual Bonus CalBonus (const Context& context) const { Bonus bonus = 0.0; cout << "PM的年终奖计算方式." << endl; //... return bonus; } }; class AccountantBonus : public BonusStategy { public: virtual Bonus CalBonus (const Context& context) const { Bonus bonus = 0.0; cout << "会计的年终奖计算方式." << endl; //... return bonus; } }; class Staff { private: BonusStategy* m_bonusStategy; public: Staff(BonusStategy* bonusStategy) : m_bonusStategy(bonusStategy){} Bonus CalBonus() const { Bonus bonus = 0.0; Context context; //Context的处理... return m_bonusStategy->CalBonus(context); } ~Staff() { delete m_bonusStategy; } }; int main() { Staff staff(new ProgrammerBonus); Bonus bonus = staff.CalBonus(); return 0; }
方案二恰好解决了方案一不足的两点。其一,每个
Staff对象中只含有要用到的年终奖计算算法,节省内存以及运行时的CPU。其二,我们可以将
BonusStategy类们和
Staff类放在不同的文件下。当我们需要增加职位时,只需要增加一个派生自
BonusStategy的子类, 对已存在的类不会产生任何影响。当我们需要改变
Staff的职位时,只需要改变其
m_bonusStategy成员变量即可。
如,当我们需要增加一个架构师职位,只需要加入下列代码即可:
class ArchitecteBonus : public BonusStategy { public: virtual Bonus CalBonus (const Context& context) const { Bonus bonus = 0.0; cout << "架构师的年终奖计算方式." << endl; //... return bonus; } };
综合以上分析,可知:
当选择的算法种类比较少,并且不会增加时,选择方案一可以在满足要求并较为完美地解决问题,并且代码简单易懂,可读性强。
当算法种类较多,或者未来增加算法的可能性较大时,选择方案二可以较好的弥补方案一的不足,可扩展性强。
3.策略模式的一般结构
相关文章推荐
- 设计模式之Strategy(策略)
- 设计模式之策略模式(strategy)--游戏角色使用武器
- [设计模式] 23.Strategy 策略模式
- [★] .NET 偶尔连接的设计策略 -联机状态- 脱机模式- 数据同步
- 设计模式袖珍版 连续转载之 - Strategy(策略)
- 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)
- 设计模式随笔系列:鸭子-策略模式(Strategy)[原]
- 设计模式之Strategy(策略)
- 设计模式之策略模式探讨初步[引]
- 设计模式随笔系列:鸭子-策略模式(Strategy)[转]
- 设计模式之Strategy(策略)
- Java设计模式学习之一---策略模式
- AspectJ实现设计模式(二)——策略模式
- 设计模式之策略模式探讨初步
- 设计模式之Strategy(策略)
- 设计模式之Strategy(策略)
- 设计模式与泡mm的关系之strategy策略模式及再思考
- 设计模式之Strategy(策略)
- 设计模式随笔系列:鸭子-策略模式(Strategy)
- 设计模式(20)-策略模式(Strategy)