Singletonパターンのメリットは
- 振る舞いを簡単に交換することが出来る。
- 振る舞いを動的に交換することが出来る。
まずは次のクラス図をご覧ください
ちゃんとクリックして拡大して見てくださいね。
このクラス図で重要なのは
- MonsterStrategyクラス
つぎにソースを見てみましょう、用意するのは次のファイルです。
- main.cpp
- Monster.h
- Monster.cpp
- MonsterStrategy.h
- MonsterStrategy.cpp
- MonsterStrategyFreedom.h
- MonsterStrategyFreedom.cpp
- MonsterStrategyGangan.h
- MonsterStrategyGangan.cpp
#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①MonsterStrategyを継承しています。//---------------------------------- // mothod //---------------------------------- // constructor MonsterStrategyGangan::MonsterStrategyGangan() { // do nothing... } // destructor MonsterStrategyGangan::~MonsterStrategyGangan() { // do nothing... } // move void MonsterStrategyGangan::move(Monster& _monster) { printf("inochi\n"); }
②オーバーライドしたmove()メソッドです。
最後にmain.cppです。
#include "Monster.h" #includevoid 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パターンの説明は終わりです。クラス数は少し多いですがそんなに難しいパターンではないはずです。
ソースコードはコピペで動かせるハズですので是非試してみてください。
0 件のコメント:
コメントを投稿