c/c++设计模式---策略模式
一个具体范例的逐步重构
Fighter.h
#ifndef __RIGHTER__ #define __RIGHTER__ ////增加补充生命值道具(药品) //enum ItemAddlife //{ // LF_BXD, //补血丹 // LF_DHD, //大还丹 // LF_SHD, //守护丹 //}; class ItemStrategy; //类前向声明 //战斗者父类 class Fighter { public: Fighter(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {} virtual ~Fighter() {} public: /* void UseItem(ItemAddlife djtype) //吃药补充生命值 { if (djtype == LF_BXD) //道具类型:补血丹 { m_life += 200;//补充200点生命值 //if (主角中毒) //{ // 停止中毒状态,也就是主角吃药后不再中毒 //} //if (主角处于狂暴状态) //{ // m_life += 400; //额外再补充400点生命值 // m_magic += 200; //魔法值也再补充200点 //} } else if (djtype == LF_DHD) //道具类型:大还丹 { m_life += 300;//补充300点生命值 } else if (djtype == LF_SHD) //道具类型:守护丹 { m_life += 500;//补充500点生命值 } //.......其他的一些判断逻辑,略。。。。。。 } */ public: void SetItemStrategy(ItemStrategy* strategy); //设置道具使用的策略 void UseItem(); //使用道具 int GetLife(); //获取人物生命值 void SetLife(int life); //设置人物生命值 protected: int m_life; int m_magic; int m_attack; ItemStrategy* itemstrategy = nullptr; //C++11中支持这样初始化 }; //“战士”类,父类为Fighter class F_Warrior :public Fighter { public: F_Warrior(int life, int magic, int attack) :Fighter(life, magic, attack) {} }; //“法师”类,父类为Fighter class F_Mage :public Fighter { public: F_Mage(int life, int magic, int attack) :Fighter(life, magic, attack) {} }; #endif
Fighter.cpp
#include <iostream> #include "Fighter.h" #include "ItemStrategy.h" using namespace std; //设置道具使用的策略 void Fighter::SetItemStrategy(ItemStrategy* strategy) { itemstrategy = strategy; } //使用道具(吃药) void Fighter::UseItem() { itemstrategy->UseItem(this); } //获取人物生命值 int Fighter::GetLife() { return m_life; } //设置人物生命值 void Fighter::SetLife(int life) { m_life = life; }
ItemStrategy.h
#ifndef _ITEMSTRATEGY__ #define _ITEMSTRATEGY__ //道具策略类的父类 class ItemStrategy { public: virtual void UseItem(Fighter* mainobj) = 0; }; //补血丹策略类 class ItemStrategy_BXD :public ItemStrategy { public: virtual void UseItem(Fighter* mainobj) { mainobj->SetLife(mainobj->GetLife() + 200); //补充200点生命值 } }; //大还丹策略类 class ItemStrategy_DHD :public ItemStrategy { public: virtual void UseItem(Fighter* mainobj) { mainobj->SetLife(mainobj->GetLife() + 300); //补充300点生命值 } }; //守护丹策略类 class ItemStrategy_SHD :public ItemStrategy { public: virtual void UseItem(Fighter* mainobj) { mainobj->SetLife(mainobj->GetLife() + 500); //补充500点生命值 } }; #endif
myproject.cpp
#include <iostream> #include "Fighter.h" #include "ItemStrategy.h" #ifdef _DEBUG //只在Debug(调试)模式下 #ifndef DEBUG_NEW #define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符 #define new DEBUG_NEW #endif #endif //#include <boost/type_index.hpp> using namespace std; //#pragma warning(disable : 4996) namespace _nmsp1 { } int main() { /* Fighter* prole_war = new F_Warrior(1000, 0, 200); //这里没有采用工厂模式,如果主角很多,可以考虑采用工厂模式创建对象 prole_war->UseItem(LF_DHD); delete prole_war; */ //创建主角 Fighter* prole_war = new F_Warrior(1000, 0, 200); //吃一颗大还丹 ItemStrategy* strategy = new ItemStrategy_DHD(); //创建大还丹策略 prole_war->SetItemStrategy(strategy); //主角设置大还丹策略,准备吃大还丹 prole_war->UseItem(); //主角吃大还丹 //再吃一颗补血丹 ItemStrategy* strategy2 = new ItemStrategy_BXD(); //创建补血丹策略 prole_war->SetItemStrategy(strategy2);//主角设置补血丹策略,准备吃补血丹 prole_war->UseItem(); //主角吃补血丹 delete strategy; delete strategy2; delete prole_war; return 0; }
策略(Strategy)模式
//(1)一个具体实现范例的逐步重构
//补血道具(药品):
//a:补血丹:补充200点生命值
//b:大还丹:补充300点生命值
//c:守护丹:补充500点生命值
//Fighter,F_Warrior,F_Mage
//策略 设计模式的定义:定义一系列算法(策略类),将每个算法封装起来,让它们可以相互替换。换句话说,策略模式通常把一系列算法
// 封装到一系列具体策略类中来作为抽象策略类的子类,然后根据实际需要使用这些子类。
//策略类中的三种角色
//a)Context(环境类):该类中维持着一个对抽象策略类的指针或引用。这里指Fighter类。
//b)Stategy(抽象策略类):定义所支持的算法的公共接口,是所有策略类的父类。这里指ItemStrategy类。
//c)ConcreteStrategy(具体策略类):抽象策略类的子类,实现抽象策略类中声明的接口。这里指ItemStrategy_BXD、ItemStrategy_DHD、ItemStrategy_SHD。
//策略类的优点:
//a)以扩展的方式支持对未来的变化,符合开闭原则。
//遇到大量不稳定的if条件分支 或者switch分支,就要优先考虑是否可以通过策略模式来解决。策略模式是if,switch条件分支的杀手。
//b)算法可以被复用。
//c)策略模式可以看成是类继承的一种替代方案。通过为环境类对象指定不同的策略,就可以改变环境类对象的行为。
//策略类的缺点:
//a)导致引入许多新策略类;
//b)使用策略时,调用者(main主函数)必须熟知所有策略类的功能并根据实际需要自行决定使用哪个策略类。
#include <iostream> #include "Fighter.h" #include "ItemStrategy.h" #ifdef _DEBUG //只在Debug(调试)模式下 #ifndef DEBUG_NEW #define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符 #define new DEBUG_NEW #endif #endif //#include <boost/type_index.hpp> using namespace std; //#pragma warning(disable : 4996) namespace _nmsp1 { class M_Undead //亡灵类怪物 { public: void getinfo() { cout << "这是一只亡灵类怪物" << endl; } //......其他代码略 }; class M_Element //元素类怪物 { public: void getinfo() { cout << "这是一只元素类怪物" << endl; } //......其他代码略 }; class M_Mechanic //机械类怪物 { public: void getinfo() { cout << "这是一只机械类怪物" << endl; } //......其他代码略 }; //战士主角 class F_Warrior { public: void attack_enemy_undead(M_Undead* pobj) //攻击亡灵类怪物 { //进行攻击处理...... pobj->getinfo(); //可以调用亡灵类怪物相关的成员函数 } public: void attack_enemy_element(M_Element* pobj) //攻击元素类怪物 { //进行攻击处理...... pobj->getinfo(); //可以调用元素类怪物相关的成员函数 } //其他代码略...... }; } namespace _nmsp2 { class Monster //作为所有怪物类的父类(抽象层) { public: virtual void getinfo() = 0; //纯虚函数 virtual ~Monster() {} //做父类时析构函数应该为虚函数 }; class M_Undead :public Monster//亡灵类怪物 { public: virtual void getinfo() { cout << "这是一只亡灵类怪物" << endl; } //......其他代码略 }; class M_Element :public Monster//元素类怪物 { public: virtual void getinfo() { cout << "这是一只元素类怪物" << endl; } //......其他代码略 }; class M_Mechanic :public Monster//机械类怪物 { public: virtual void getinfo() { cout << "这是一只机械类怪物" << endl; } //......其他代码略 }; //战士主角 class F_Warrior { public: void attack_enemy(Monster* pobj) //攻击怪物 { //进行攻击处理...... pobj->getinfo(); //可以调用怪物相关的成员函数 } //其他代码略...... }; } int main() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口 //第4章 策略(Strategy)模式 //(1)一个具体实现范例的逐步重构 //补血道具(药品): //a:补血丹:补充200点生命值 //b:大还丹:补充300点生命值 //c:守护丹:补充500点生命值 //Fighter,F_Warrior,F_Mage //策略 设计模式的定义:定义一系列算法(策略类),将每个算法封装起来,让它们可以相互替换。换句话说,策略模式通常把一系列算法 // 封装到一系列具体策略类中来作为抽象策略类的子类,然后根据实际需要使用这些子类。 //策略类中的三种角色 //a)Context(环境类):该类中维持着一个对抽象策略类的指针或引用。这里指Fighter类。 //b)Stategy(抽象策略类):定义所支持的算法的公共接口,是所有策略类的父类。这里指ItemStrategy类。 //c)ConcreteStrategy(具体策略类):抽象策略类的子类,实现抽象策略类中声明的接口。这里指ItemStrategy_BXD、ItemStrategy_DHD、ItemStrategy_SHD。 //策略类的优点: //a)以扩展的方式支持对未来的变化,符合开闭原则。 //遇到大量不稳定的if条件分支 或者switch分支,就要优先考虑是否可以通过策略模式来解决。策略模式是if,switch条件分支的杀手。 //b)算法可以被复用。 //c)策略模式可以看成是类继承的一种替代方案。通过为环境类对象指定不同的策略,就可以改变环境类对象的行为。 //策略类的缺点: //a)导致引入许多新策略类; //b)使用策略时,调用者(main主函数)必须熟知所有策略类的功能并根据实际需要自行决定使用哪个策略类。 //(2)依赖倒置原则:Dependency Inversion Principle,简称DIP //是面向独享设计的主要实现方法,同时 也是实现开闭原则的重要实现途径。 //解释:高层组件不应该依赖于低层(具体实现类),两者都应该依赖于抽象层。 //范例:工厂模式时,亡灵类M_Undead,元素类M_Element,机械类M_Mechanic。 /* Fighter* prole_war = new F_Warrior(1000, 0, 200); //这里没有采用工厂模式,如果主角很多,可以考虑采用工厂模式创建对象 prole_war->UseItem(LF_DHD); delete prole_war; */ /* //创建主角 Fighter* prole_war = new F_Warrior(1000, 0, 200); //吃一颗大还丹 ItemStrategy* strategy = new ItemStrategy_DHD(); //创建大还丹策略 prole_war->SetItemStrategy(strategy); //主角设置大还丹策略,准备吃大还丹 prole_war->UseItem(); //主角吃大还丹 //再吃一颗补血丹 ItemStrategy* strategy2 = new ItemStrategy_BXD(); //创建补血丹策略 prole_war->SetItemStrategy(strategy2);//主角设置补血丹策略,准备吃补血丹 prole_war->UseItem(); //主角吃补血丹 delete strategy; delete strategy2; delete prole_war; */ /* _nmsp1::M_Undead* pobjud = new _nmsp1::M_Undead(); _nmsp1::F_Warrior* pobjwar = new _nmsp1::F_Warrior(); pobjwar->attack_enemy_undead(pobjud); //攻击一只亡灵类怪物 _nmsp1::M_Element* pobjelm = new _nmsp1::M_Element(); pobjwar->attack_enemy_element(pobjelm); //攻击一只元素类怪物 //资源释放 delete pobjwar; delete pobjud; delete pobjelm;*/ _nmsp2::Monster* pobjud = new _nmsp2::M_Undead(); _nmsp2::F_Warrior* pobjwar = new _nmsp2::F_Warrior(); pobjwar->attack_enemy(pobjud); //攻击一只亡灵类怪物 _nmsp2::Monster* pobjelm = new _nmsp2::M_Element(); pobjwar->attack_enemy(pobjelm); //攻击一只元素类怪物 //资源释放 delete pobjwar; delete pobjud; delete pobjelm; return 0; }