Strategyパターンはアルゴリズム(振る舞い)をカプセル化(クラス化)するパターンです。
Singletonパターンのメリットは
- 振る舞いを簡単に交換することが出来る。
- 振る舞いを動的に交換することが出来る。
です。
まずは次のクラス図をご覧ください
見ました?なんか複雑だからってあんまり見てないでしょ?
ちゃんとクリックして拡大して見てくださいね。
このクラス図で重要なのは
ですMonsterのmove()の振る舞いをMonsterStrategyクラスに委譲しています。
つぎにソースを見てみましょう、用意するのは次のファイルです。
- main.cpp
- Monster.h
- Monster.cpp
- MonsterStrategy.h
- MonsterStrategy.cpp
- MonsterStrategyFreedom.h
- MonsterStrategyFreedom.cpp
- MonsterStrategyGangan.h
- MonsterStrategyGangan.cpp
まずは
Monster.hです。
#ifndef _MONSTER_H_
#define _MONSTER_H_
#include "MonsterStrategy.h"
class Monster
{
//----------------------------------
// constant
//----------------------------------
#define STRATEGY_MAX_NUM 8
//----------------------------------
// field
//----------------------------------
private:
MonsterStrategy* m_strategyDictionary[STRATEGY_MAX_NUM]; // ①
MonsterStrategy::Type m_currentStrategyType; // ②
//----------------------------------
// property
//----------------------------------
public:
const MonsterStrategy::Type getCurrentStrategyType();
Monster& setCurrentStrategyType(const MonsterStrategy::Type _type);
private:
MonsterStrategy** getStrategyDictionary();
const bool addStrategy(const MonsterStrategy::Type _type);
//----------------------------------
// mothod
//----------------------------------
public:
// constructor
Monster();
// destructor
~Monster();
// initialize
const bool init();
// move
Monster& move(); // ③
private:
// operator(=)
Monster& operator=(const Monster& _monster);
};
#endif
①Monsterの行動アルゴリズム辞書です。今回は配列を使用していますがDictionary系クラスを私用するのが良いでしょう。
②現在の行動アルゴリズムです。
③Monsterに行動指示を出します。
次に
Monster.cppです。
#include "Monster.h"
#include "MonsterStrategyFreedom.h"
#include "MonsterStrategyGangan.h"
#include
//-----------------------------------
// property
//-----------------------------------
const MonsterStrategy::Type Monster::getCurrentStrategyType()
{
return this->m_currentStrategyType;
}
Monster& Monster::setCurrentStrategyType(const MonsterStrategy::Type _type)
{
printf("strategy %d -> %d\n", this->getCurrentStrategyType(), _type);
this->m_currentStrategyType = _type;
return *this;
}
MonsterStrategy** Monster::getStrategyDictionary()
{
return this->m_strategyDictionary;
}
const bool Monster::addStrategy(const MonsterStrategy::Type _type)
{
if (STRATEGY_MAX_NUM <= _type) {
throw "error strategy max num";
}
MonsterStrategy** strategyDictionary = this->getStrategyDictionary();
if (strategyDictionary[_type] != NULL) {
// already exist
return false;
}
switch (_type) {
case MonsterStrategy::ST_FREEDOM:
strategyDictionary[_type] = new MonsterStrategyFreedom();
break;
case MonsterStrategy::ST_GANGAN:
strategyDictionary[_type] = new MonsterStrategyGangan();
break;
default:
throw "invalid type";
break;
}
return true;
}
//-----------------------------------
// method
//-----------------------------------
// constructor
Monster::Monster() :
m_currentStrategyType(MonsterStrategy::ST_FREEDOM)
{
// do nothing...
}
// destructor
Monster::~Monster()
{
MonsterStrategy** strategyDictionary = this->getStrategyDictionary();
for (int i = 0; i < STRATEGY_MAX_NUM; i++) {
delete strategyDictionary[i];
}
}
// initialize
const bool Monster::init()
{
MonsterStrategy** strategyDictionary = this->getStrategyDictionary();
for (int i = 0; i < STRATEGY_MAX_NUM; i++) {
strategyDictionary[i] = NULL;
}
const MonsterStrategy::Type strategyTypeArray[] = {
MonsterStrategy::ST_FREEDOM,
MonsterStrategy::ST_GANGAN,
};
const int size = sizeof(strategyTypeArray) / sizeof(MonsterStrategy::Type); // ①
for (int i = 0; i < size; i++) {
this->addStrategy(strategyTypeArray[i]);
}
return true;
}
// move
Monster& Monster::move()
{
MonsterStrategy** strategyDictionary = this->getStrategyDictionary();
strategyDictionary[this->getCurrentStrategyType()]->move(*this);
return *this;
}
①配列のサイズを求めています。
次に
MonsterStrategy.hです。
#ifndef _MONSTER_STRATEGY_H_
#define _MONSTER_STRATEGY_H_
class Monster;
class MonsterStrategy
{
public:
//----------------------------------
// constant
//----------------------------------
enum Type {
ST_FREEDOM = 0, // 自由
ST_GANGAN, // がんがん行こうぜ
}; // ①
//----------------------------------
// mothod
//----------------------------------
public:
// constructor
MonsterStrategy();
// destructor
virtual ~MonsterStrategy();
// move
virtual void move(Monster& _monster) = 0; // ②
private:
// operator(=)
MonsterStrategy& operator=(const MonsterStrategy& _monsterStrategy);
};
#endif
①Monsterの行動アルゴリズムのタイプです。
②Monsterの行動アルゴリズムが記述されているメソッドです。タイプ毎にアルゴリズムは違うので純粋仮想関数にしています。
次にMonsterStrategy.cppです。
#include "MonsterStrategy.h"
#include
//----------------------------------
// mothod
//----------------------------------
// constructor
MonsterStrategy::MonsterStrategy()
{
// do nothing...
}
// destructor
MonsterStrategy::~MonsterStrategy()
{
// do nothing...
}
特に何も実装はなしです。
次に
MonsterStrategyFreedom.h
MonsterStrategyFreedom.cpp
MonsterStrategyGangan.h
MonsterStrategyGangan.cpp
をまとめて記述します。
#ifndef _MONSTER_STRATEGY_FREEDOM_H_
#define _MONSTER_STRATEGY_FREEDOM_H_
#include "MonsterStrategy.h"
class Monster;
class MonsterStrategyFreedom : public MonsterStrategy // ①
{
public:
//----------------------------------
// mothod
//----------------------------------
public:
// constructor
MonsterStrategyFreedom();
// destructor
~MonsterStrategyFreedom();
// move
void move(Monster& _monster); // ②
private:
// operator(=)
MonsterStrategyFreedom& operator=(const MonsterStrategyFreedom& _monsterStrategyFreedom);
};
#endif
#include "MonsterStrategyFreedom.h"
#include "MonsterStrategy.h"
#include "Monster.h"
#include
//----------------------------------
// mothod
//----------------------------------
// constructor
MonsterStrategyFreedom::MonsterStrategyFreedom()
{
// do nothing...
}
// destructor
MonsterStrategyFreedom::~MonsterStrategyFreedom()
{
// do nothing...
}
// move
void MonsterStrategyFreedom::move(Monster& _monster)
{
printf("freedom\n");
}
#ifndef _MONSTER_STRATEGY_GANGAN_H_
#define _MONSTER_STRATEGY_GANGAN_H_
#include "MonsterStrategy.h"
class Monster;
class MonsterStrategyGangan : public MonsterStrategy // ①
{
public:
//----------------------------------
// mothod
//----------------------------------
public:
// constructor
MonsterStrategyGangan();
// destructor
~MonsterStrategyGangan();
// move
void move(Monster& _monster); // ②
private:
// operator(=)
MonsterStrategyGangan& operator=(const MonsterStrategyGangan& _monsterStrategyGangan);
};
#endif
#include "MonsterStrategyGangan.h"
#include "MonsterStrategy.h"
#include "Monster.h"
#include
//----------------------------------
// mothod
//----------------------------------
// constructor
MonsterStrategyGangan::MonsterStrategyGangan()
{
// do nothing...
}
// destructor
MonsterStrategyGangan::~MonsterStrategyGangan()
{
// do nothing...
}
// move
void MonsterStrategyGangan::move(Monster& _monster)
{
printf("inochi\n");
}
①MonsterStrategyを継承しています。
②オーバーライドしたmove()メソッドです。
最後に
main.cppです。
#include "Monster.h"
#include
void main(void)
{
Monster monster; // モンスター生成
monster.init(); // 初期化
monster.move(); // move
monster.setCurrentStrategyType(MonsterStrategy::ST_GANGAN); // 戦略変更
monster.move(); // move
printf("hit any key...");
while(getchar() == EOF){}
}
以上で
Strategyパターンの説明は終わりです。クラス数は少し多いですがそんなに難しいパターンではないはずです。
ソースコードはコピペで動かせるハズですので是非試してみてください。