策略模式(Strategy Pattern)属于行为型模式
在策略模式下,在情境中的一个对象可执行的行为或算法会随着策略对象的改变而变化,因此策略模式又被归类为行为模式。
实例:微波炉加热模式根據需求可以調整、服装搭配、数学运算套用不同算式。
适合使用此模式的情況主要有这些:
1. 一个系统需要在不同情況下动态地在多种算法或行为当中选择一种来执行。
2. 一个对象可以执行多种不同的算法或行为,使用多重条件分支语句(if...else)将难以维护与管理。
3. 一个系统中有多个不同的类,它们的区别只在于它们封装的算法或行为不同。 (相同之处也许是可执行行为的对象相同,又或是其它)
因此使用策略模式集中管理,可發現有点类似工厂模式的感覺。
使用策略模式的优点:
1. 用策略模式做集中管理可以为相关的算法或行为制定一个算法族或行为族,同时增强了相关算法的可扩展性;
有策略性的设计算法族或行为族结构,可以适时地将公用代码写在父类,避免代码冗余。
2. 可避免使用多重条件分支语句,有效划清了选择使用算法或行为的逻辑与算法或行为本身的逻辑彼此存在的位置,
让各自负责的范围更加明确,也方便代码维护。
使用策略模式的缺点:
1. 由于需要把每个具体可用的算法或行为封装成策略类,故策略类可能会很多。
2. 所有的策略类都必须公开暴露,才能让情境中的使用者调用,同时我们也必须假设使用者知晓所有的算法或行为。
以下是策略模式所呈现出的类别图:
本篇文章所实作的应用实例情境如下:
玩家可选择想使用的技能。
玩家根据已选择的技能发动该技能。
每个技能都有各自的伤害计算公式,并且封装在类中,使用策略模式集中管理。
实作代码如下:
策略类interface
[SkillStrategy.h]
// This is a strategy interface of skill.
#pragma once
class SkillStrategy
{
public:
SkillStrategy(void)
{
}
~SkillStrategy(void)
{
}
virtual int calculateDamage(int atk) = 0; // return damage value
};
策略实现类(技能)
[MegaPunch.h]
#pragma once
#include "skillstrategy.h"
class MegaPunch :
public SkillStrategy
{
public:
MegaPunch(void);
~MegaPunch(void);
int calculateDamage(int atk); // return damage value
};
[MegaPunch.cpp]
#include "MegaPunch.h"
MegaPunch::MegaPunch(void)
{
}
MegaPunch::~MegaPunch(void)
{
}
int MegaPunch::calculateDamage(int atk)
{
return (atk+200)/2;
}
[Slash.h]
#pragma once
#include "skillstrategy.h"
class Slash :
public SkillStrategy
{
public:
Slash(void);
~Slash(void);
int calculateDamage(int atk); // return damage value
};
[Slash.cpp]
#include "Slash.h"
Slash::Slash(void)
{
}
Slash::~Slash(void)
{
}
int Slash::calculateDamage(int atk)
{
return (atk+32)/3;
}
情境類
[Character.h]
#pragma once
#include <iostream>
#include <string>
#include "SkillStrategy.h"
using namespace std;
class Character
{
public:
Character(void) : name("NoName"), atk(1), strategy(NULL) {};
Character(string str) : name(str), atk(1), strategy(NULL) {};
~Character(void);
void setSkill(SkillStrategy *strategy);
int useSkill(); // return damage value
string getName();
void setAtk(int atk);
private:
SkillStrategy *strategy;
string name;
int atk;
};
[Character.cpp]
#include "Character.h"
Character::~Character(void)
{
delete this->strategy;
}
void Character::setSkill(SkillStrategy *strategy)
{
this->strategy = strategy;
}
int Character::useSkill()
{
if(this->strategy == NULL)
{
printf("No skill has been chosen!\nPlease choose a skill.\n");
return 0;
}
return strategy->calculateDamage(this->atk);
}
string Character::getName()
{
return this->name;
}
void Character::setAtk(int atk)
{
if(atk>0 && atk<1000)
this->atk = atk;
else
atk = 1;
}
主程序
[StrategyPatternDemo.cpp]
#include <iostream>
using namespace std;
#include "Character.h"
#include "MegaPunch.h"
#include "Slash.h"
void printInfo(string name, int damage)
{
cout<<name<<" make "<<damage<<" points damages."<<endl;
}
void main()
{
SkillStrategy *megaPunch = new MegaPunch();
SkillStrategy *slash = new Slash();
Character *player = new Character("KungFuDog");
player->setAtk(100);
player->setSkill(megaPunch);
printInfo(player->getName(), player->useSkill());
player->setSkill(slash);
printInfo(player->getName(), player->useSkill());
getchar();
return;
}
Output:
KungFuDog make 150 points damages.
KungFuDog make 44 points damages.
工程就不打包了,程序没有很复杂,应该很容易看明白,
之所以把关键部分类定义和实现分开,是希望能够将设计模式观念明确,也希望能够养成良好编程习惯。