策略模式
策略模式是指定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。也就是说这些算法所完成的功能一样,对外的接口一样,只是各自实现上存在差异。用策略模式来封装算法,效果比较好。
优点:
1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象
以CS里的人物作为例子,每个人都可以有几个武器,武器之间动态切换,武器拥有统一的攻击命令,首先给出替换算法的定义:
//抽象接口 class WeaponBehavior { public: virtual void useWeapon() = 0; };
//三种具体的替换算法 class AK47 : public WeaponBehavior { public: void useWeapon() { cout<< "Use AK47 to shoot!" <<endl; } }; class Knife : public WeaponBehavior { public: void useWeapon() { cout<< "Use Knife to kill!" <<endl; } };
class Rifle : public WeaponBehavior { public: void useWeapon() { cout<< "Use Rifle to shoot!" <<endl; } };
接着给出角色Character的定义,这里很关键,Character的实现方式直接影响了用户的使用方式,其关键在于如何指定替换算法。
方式一
直接通过参数指定,传入一个特定算法的指针:
//Character需要用到替换算法 class Character { public: Character() { weapon = 0; } void setWeapon(WeaponBehavior *w)
{
this->weapon = w;
} void virtual fight() = 0; protected: WeaponBehavior *weapon; }; class King:public Character { public: void fight() { if ( this->weapon == NULL)
{
cout << "You don't have a weapon! Please Set Weapon!" << endl;
} else
{
weapon->useWeapon();
} } }; int main() { Character *kin = new King(); kin->fight();
WeaponBehavior *ak47 = new AK47(); kin->setWeapon(ak47); //暴露了算法的定义 kin->fight();
if(kin) delete kin; return 0; }
方式二
也是直接通过参数指定,只不过不是传入指针,而是一个标签。这样用户只要知道算法的相应标签即可,而不需要知道算法的具体定义。
//Character需要用到替换算法 enum WEAPON {WEAPON_AK, WEAPON_KNIFE, WEAPON_RIFLE}; //标签 class Character { public: Character() { weapon = 0; } void setWeapon(enum WEAPON w) { if(w == WEAPON_AK) weapon = new AK47(); else if(w == WEAPON_KNIFE) weapon = new Knife(); else if(w == WEAPON_RIFLE) weapon = new Rifle(); else weapon = NULL; } void virtual fight() = 0; protected: WeaponBehavior *weapon; }; class King:public Character { public: void fight() { if ( this->weapon == NULL) { cout << "You don't have a weapon! Please Set Weapon!" << endl; } else { weapon->useWeapon(); } } }; int main() { Character *kin = new King(); kin->fight(); kin->setWeapon(WEAPON_AK); kin->fight(); if(kin) delete kin; return 0; }
相比方式一,这种方式用起来方便多了。其实这种方式将简单工厂模式与策略模式结合在一起,算法的定义使用了策略模式,而Character的定义其实使用了简单工厂模式。