定义
策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
Strategy 模式典型的结构图为:
大家肯定看着很懵逼,其实第一次接触类图的时候我自己也是这样。
那么咱们举个例子来解释一下。
假设我们要实现一个角色游戏,context为所有角色的基类(例子的代码后面会实现,此处只是拿context举例,此处的context并不是基类),一个角色可以切换不同的武器。然后strategy则为不同的武器的基类,而不同的武器的攻击方式是不同的,斧头的攻击为砍,剑的攻击为刺,弓箭的话为射击。乍一看感觉好麻烦啊。难不成得给一个角色类把所有的武器类都包含进去,然后切换武器的时候删除掉之前的武器,然后再重新开辟一个新的武器类。这样子的话给我们设计会带来非常大的不方便。而且假如我们有了新的武器,比如魔法棒,那么我们不是应该给角色类里面再添加魔法棒类,这样的话会让角色类变得非常庞大,而且非常不利于后期的维护,我们不能每增加一个武器就给角色类添加一个武器类吧。所以我们在设计的时候要让系统不去担心任何改变(武器的添加与更改),此时策略模式将会是一个不错的选择。
首先咱们先根据类图实现一下代码。关于武器的代码咱们后面实现。
代码
context.h
#ifndef STRATEGY_CONTEXT_H
#define STRATEGY_CONTEXT_H
#include "context.h"
#include "strategy.h"
#include <iostream>
using namespace std;
class Context
{
public:
Context(Strategy* stg);
~Context();
void DoAction();
protected:
Strategy* _stg;
};
Context::Context(Strategy* stg)
{
_stg = stg;
}
Context::~Context()
{
if(!_stg)
delete _stg;
}
void Context::DoAction()
{
_stg->AlgrithmInterface();
}
#endif //STRATEGY_CONTEXT_H
strategy.h
#include "strategy.h"
#include <iostream>
using namespace std;
class Strategy
{
public:
Strategy();
virtual ~Strategy();
virtual void AlgrithmInterface() = 0;
};
class ConcreteStrategyA : public Strategy
{
public:
ConcreteStrategyA();
virtual ~ConcreteStrategyA();
void AlgrithmInterface();
};
class ConcreteStrategyB : public Strategy
{
public:
ConcreteStrategyB();
virtual ~ConcreteStrategyB();
void AlgrithmInterface();
};
Strategy::Strategy()
{
}
Strategy::~Strategy()
{
cout << "~Strategy....." << endl;
}
ConcreteStrategyA::ConcreteStrategyA()
{
cout << "test ConcreteStrategyA......" << endl;
}
ConcreteStrategyA::~ConcreteStrategyA()
{
cout << "~test ConcreteStrategyA......" << endl;
}
void ConcreteStrategyA::AlgrithmInterface() {
cout << "GUA GUA" << endl;
}
ConcreteStrategyB::ConcreteStrategyB()
{
cout << "test ConcreteStrategyB......" << endl;
}
ConcreteStrategyB::~ConcreteStrategyB()
{
cout << "~test ConcreteStrategyB......" << endl;
}
void ConcreteStrategyB::AlgrithmInterface()
{
cout << "test ConcreteStrategyB......" << endl;
}
main.cpp
#include "context.h"
#include "strategy.h"
#include <iostream>
using namespace std;
int main()
{
Strategy* ps = new ConcreteStrategyA();
Context* pc = new Context(ps);
pc->DoAction();
if(pc != NULL)
{
delete pc;
}
return 0;
}
这里面Strategy为虚基类,具体的策略继承自Strategy,而在Context中有一个Strategy的指针,该指针可以指向Strategy的所有子类,又因为Strategy中的AlgrithmInterface为虚函数,根据多态,Strategy指针调用AlgrithmInterface调用的实际是子类的AlgrithmInterface函数。这样的话Context中只需要一个Strategy成员即可调用任何Strategy的子类。
策略模式的应用
下面我们来将上面的角色和武器的例子进行代码的实现,从而更好的理解策略模式。
main.cpp
#include <iostream>
#include "Character.h"
#include "Weapon.h"
using std::cout;
using std::endl;
int main()
{
Character** characters = new Character*[3];
Weapon** weapons = new Weapon*[4];
characters[0] = new King();
characters[1] = new Queen();
characters[2] = new Knight();
weapons[0] = new Sword();
weapons[1] = new Knife();
weapons[2] = new Axe();
weapons[3] = new BowAndArrow();
characters[0]->setWeapon(weapons[0]);
characters[1]->setWeapon(weapons[1]);
characters[2]->setWeapon(weapons[2]);
for(int i = 0; i < 3; ++i)
{
characters[i]->fight();
}
characters[2]->setWeapon(weapons[3]);
characters[2]->fight();
delete[] characters;
delete[] weapons;
}
Weapon.h
#ifndef STRATEGY_TEST_WEAPON_H
#define STRATEGY_TEST_WEAPON_H
#include <iostream>
using std::cout;
using std::endl;
class Weapon
{
public:
Weapon()
{}
virtual ~Weapon() {}
virtual void useWeapon() = 0;
};
class Sword : public Weapon
{
void useWeapon()
{
cout << "宝剑挥舞" << endl;
}
};
class Knife : public Weapon
{
void useWeapon()
{
cout << "匕首刺杀" << endl;
}
};
class Axe : public Weapon
{
void useWeapon()
{
cout << "斧头劈砍" << endl;
}
};
class BowAndArrow : public Weapon
{
void useWeapon()
{
cout << "弓箭射击" << endl;
}
};
#endif //STRATEGY_TEST_WEAPON_H
Character.h
#ifndef STRATEGY_TEST_CHARACTER_H
#define STRATEGY_TEST_CHARACTER_H
#include "Weapon.h"
class Character
{
protected:
Weapon* weapon;
public:
Character()
{
this->weapon = nullptr;
}
virtual ~Character() {}
void setWeapon(Weapon* weapon)
{
this->weapon=weapon;
}
virtual void fight() = 0;
};
class King : public Character //国王类
{
void fight()
{
this->weapon->useWeapon();
}
};
class Queen : public Character //皇后类
{
void fight()
{
this->weapon->useWeapon();
}
};
class Knight : public Character //骑士类
{
void fight()
{
this->weapon->useWeapon();
}
};
#endif //STRATEGY_TEST_CHARACTER_H
Character(角色)为抽象类,由具体的角色(King, Queen, Knight)来继承。
Weapon(武器)也属于抽象类,由具体的武器(Sword, Knife, BowAndArrow, Axe)来继承。
换武器的话可以调用setWeapon(),战斗过程(fight)中可以调用useWeapon()进行攻击。