2010年5月9日日曜日

C++でStrategyパターン

Strategyパターンはアルゴリズム(振る舞い)をカプセル化(クラス化)するパターンです。
Singletonパターンのメリットは
  • 振る舞いを簡単に交換することが出来る。
  • 振る舞いを動的に交換することが出来る。
です。
まずは次のクラス図をご覧ください

見ました?なんか複雑だからってあんまり見てないでしょ?
ちゃんとクリックして拡大して見てくださいね。
このクラス図で重要なのは
  • MonsterStrategyクラス
ですMonsterのmove()の振る舞いをMonsterStrategyクラスに委譲しています。
つぎにソースを見てみましょう、用意するのは次のファイルです。

  • main.cpp
  • Monster.h
  • Monster.cpp
  • MonsterStrategy.h
  • MonsterStrategy.cpp
  • MonsterStrategyFreedom.h
  • MonsterStrategyFreedom.cpp
  • MonsterStrategyGangan.h
  • MonsterStrategyGangan.cpp
まずはMonster.hです。
  1. #ifndef _MONSTER_H_  
  2. #define _MONSTER_H_  
  3.   
  4. #include "MonsterStrategy.h"  
  5.   
  6. class Monster  
  7. {  
  8.     //----------------------------------  
  9.     // constant  
  10.     //----------------------------------  
  11.     #define STRATEGY_MAX_NUM 8  
  12.   
  13.     //----------------------------------  
  14.     // field  
  15.     //----------------------------------  
  16. private:  
  17.     MonsterStrategy* m_strategyDictionary[STRATEGY_MAX_NUM];    //  ①  
  18.     MonsterStrategy::Type m_currentStrategyType;                //  ②  
  19.   
  20.     //----------------------------------  
  21.     // property  
  22.     //----------------------------------  
  23. public:  
  24.     const MonsterStrategy::Type getCurrentStrategyType();  
  25.     Monster& setCurrentStrategyType(const MonsterStrategy::Type _type);  
  26.   
  27. private:  
  28.     MonsterStrategy** getStrategyDictionary();  
  29.     const bool addStrategy(const MonsterStrategy::Type _type);  
  30.   
  31.     //----------------------------------  
  32.     // mothod  
  33.     //----------------------------------  
  34. public:  
  35.     // constructor  
  36.     Monster();  
  37.   
  38.     // destructor  
  39.     ~Monster();  
  40.   
  41.     // initialize  
  42.     const bool init();  
  43.   
  44.     // move  
  45.     Monster& move();    //  ③  
  46.   
  47. private:  
  48.     // operator(=)  
  49.     Monster& operator=(const Monster& _monster);  
  50. };  
  51. #endif  
①Monsterの行動アルゴリズム辞書です。今回は配列を使用していますがDictionary系クラスを私用するのが良いでしょう。
②現在の行動アルゴリズムです。
③Monsterに行動指示を出します。

次にMonster.cppです。
  1. #include "Monster.h"  
  2. #include "MonsterStrategyFreedom.h"  
  3. #include "MonsterStrategyGangan.h"  
  4. #include <stdio.h>  
  5.   
  6. //-----------------------------------  
  7. // property  
  8. //-----------------------------------  
  9. const MonsterStrategy::Type Monster::getCurrentStrategyType()  
  10. {  
  11.     return this->m_currentStrategyType;  
  12. }  
  13. Monster& Monster::setCurrentStrategyType(const MonsterStrategy::Type _type)  
  14. {  
  15.     printf("strategy %d -> %d\n"this->getCurrentStrategyType(), _type);  
  16.     this->m_currentStrategyType = _type;  
  17.     return *this;  
  18. }  
  19. MonsterStrategy** Monster::getStrategyDictionary()  
  20. {  
  21.     return this->m_strategyDictionary;  
  22. }  
  23. const bool Monster::addStrategy(const MonsterStrategy::Type _type)  
  24. {  
  25.     if (STRATEGY_MAX_NUM <= _type) {  
  26.         throw "error strategy max num";  
  27.     }  
  28.     MonsterStrategy** strategyDictionary = this->getStrategyDictionary();  
  29.     if (strategyDictionary[_type] != NULL) {  
  30.         // already exist  
  31.         return false;  
  32.     }  
  33.   
  34.     switch (_type) {  
  35.         case MonsterStrategy::ST_FREEDOM:  
  36.             strategyDictionary[_type] = new MonsterStrategyFreedom();  
  37.             break;  
  38.         case MonsterStrategy::ST_GANGAN:  
  39.             strategyDictionary[_type] = new MonsterStrategyGangan();  
  40.             break;  
  41.         default:  
  42.             throw "invalid type";  
  43.             break;  
  44.     }  
  45.   
  46.     return true;  
  47. }  
  48.   
  49. //-----------------------------------  
  50. // method  
  51. //-----------------------------------  
  52. // constructor  
  53. Monster::Monster() :  
  54.     m_currentStrategyType(MonsterStrategy::ST_FREEDOM)  
  55. {  
  56.     // do nothing...  
  57. }  
  58. // destructor  
  59. Monster::~Monster()  
  60. {  
  61.     MonsterStrategy** strategyDictionary = this->getStrategyDictionary();  
  62.     for (int i = 0; i < STRATEGY_MAX_NUM; i++) {  
  63.         delete strategyDictionary[i];  
  64.     }  
  65.   
  66. }  
  67.   
  68. // initialize  
  69. const bool Monster::init()  
  70. {  
  71.     MonsterStrategy** strategyDictionary = this->getStrategyDictionary();  
  72.     for (int i = 0; i < STRATEGY_MAX_NUM; i++) {  
  73.         strategyDictionary[i] = NULL;  
  74.     }  
  75.   
  76.     const MonsterStrategy::Type strategyTypeArray[] = {  
  77.         MonsterStrategy::ST_FREEDOM,  
  78.         MonsterStrategy::ST_GANGAN,  
  79.     };  
  80.     const int size = sizeof(strategyTypeArray) / sizeof(MonsterStrategy::Type); //  ①  
  81.     for (int i = 0; i < size; i++) {  
  82.         this->addStrategy(strategyTypeArray[i]);  
  83.     }  
  84.   
  85.     return true;  
  86. }  
  87.   
  88. // move  
  89. Monster& Monster::move()  
  90. {  
  91.     MonsterStrategy** strategyDictionary = this->getStrategyDictionary();  
  92.     strategyDictionary[this->getCurrentStrategyType()]->move(*this);  
  93.     return *this;  
  94. }  
  95. </stdio.h>  
①配列のサイズを求めています。

次にMonsterStrategy.hです。
  1. #ifndef _MONSTER_STRATEGY_H_  
  2. #define _MONSTER_STRATEGY_H_  
  3.   
  4. class Monster;  
  5.   
  6. class MonsterStrategy  
  7. {  
  8. public:  
  9.     //----------------------------------  
  10.     // constant  
  11.     //----------------------------------  
  12.     enum Type {  
  13.         ST_FREEDOM = 0, // 自由  
  14.         ST_GANGAN,  // がんがん行こうぜ  
  15.     };  //  ①  
  16.   
  17.     //----------------------------------  
  18.     // mothod  
  19.     //----------------------------------  
  20. public:  
  21.     // constructor  
  22.     MonsterStrategy();  
  23.   
  24.     // destructor  
  25.     virtual ~MonsterStrategy();  
  26.   
  27.     // move  
  28.     virtual void move(Monster& _monster) = 0;   //  ②  
  29.   
  30. private:  
  31.     // operator(=)  
  32.     MonsterStrategy& operator=(const MonsterStrategy& _monsterStrategy);  
  33.   
  34. };  
  35. #endif  
①Monsterの行動アルゴリズムのタイプです。
②Monsterの行動アルゴリズムが記述されているメソッドです。タイプ毎にアルゴリズムは違うので純粋仮想関数にしています。

次にMonsterStrategy.cppです。
  1. #include "MonsterStrategy.h"  
  2. #include <stdio.h>  
  3.   
  4. //----------------------------------  
  5. // mothod  
  6. //----------------------------------  
  7. // constructor  
  8. MonsterStrategy::MonsterStrategy()  
  9. {  
  10.     // do nothing...  
  11. }  
  12.   
  13. // destructor  
  14. MonsterStrategy::~MonsterStrategy()  
  15. {  
  16.     // do nothing...  
  17. }  
  18. </stdio.h>  
特に何も実装はなしです。
次に
MonsterStrategyFreedom.h
MonsterStrategyFreedom.cpp
MonsterStrategyGangan.h
MonsterStrategyGangan.cpp
をまとめて記述します。
  1. #ifndef _MONSTER_STRATEGY_FREEDOM_H_  
  2. #define _MONSTER_STRATEGY_FREEDOM_H_  
  3.   
  4. #include "MonsterStrategy.h"  
  5.   
  6. class Monster;  
  7.   
  8. class MonsterStrategyFreedom : public MonsterStrategy // ①  
  9. {  
  10. public:  
  11.   
  12.     //----------------------------------  
  13.     // mothod  
  14.     //----------------------------------  
  15. public:  
  16.     // constructor  
  17.     MonsterStrategyFreedom();  
  18.   
  19.     // destructor  
  20.     ~MonsterStrategyFreedom();  
  21.   
  22.     // move  
  23.     void move(Monster& _monster);   //  ②  
  24.   
  25. private:  
  26.     // operator(=)  
  27.     MonsterStrategyFreedom& operator=(const MonsterStrategyFreedom& _monsterStrategyFreedom);  
  28.   
  29. };  
  30. #endif  
  1. #include "MonsterStrategyFreedom.h"  
  2. #include "MonsterStrategy.h"  
  3. #include "Monster.h"  
  4. #include <stdio.h>  
  5.   
  6. //----------------------------------  
  7. // mothod  
  8. //----------------------------------  
  9. // constructor  
  10. MonsterStrategyFreedom::MonsterStrategyFreedom()  
  11. {  
  12.     // do nothing...  
  13. }  
  14.   
  15. // destructor  
  16. MonsterStrategyFreedom::~MonsterStrategyFreedom()  
  17. {  
  18.     // do nothing...  
  19. }  
  20.   
  21. // move  
  22. void MonsterStrategyFreedom::move(Monster& _monster)  
  23. {  
  24.     printf("freedom\n");  
  25. }</stdio.h>  
  1. #ifndef _MONSTER_STRATEGY_GANGAN_H_  
  2. #define _MONSTER_STRATEGY_GANGAN_H_  
  3.   
  4. #include "MonsterStrategy.h"  
  5.   
  6. class Monster;  
  7.   
  8. class MonsterStrategyGangan : public MonsterStrategy    //  ①  
  9. {  
  10. public:  
  11.   
  12.     //----------------------------------  
  13.     // mothod  
  14.     //----------------------------------  
  15. public:  
  16.     // constructor  
  17.     MonsterStrategyGangan();  
  18.   
  19.     // destructor  
  20.     ~MonsterStrategyGangan();  
  21.   
  22.     // move  
  23.     void move(Monster& _monster);   //  ②  
  24.   
  25. private:  
  26.     // operator(=)  
  27.     MonsterStrategyGangan& operator=(const MonsterStrategyGangan& _monsterStrategyGangan);  
  28.   
  29. };  
  30. #endif  
  1. #include "MonsterStrategyGangan.h"  
  2. #include "MonsterStrategy.h"  
  3. #include "Monster.h"  
  4. #include <stdio.h>  
  5.   
  6. //----------------------------------  
  7. // mothod  
  8. //----------------------------------  
  9. // constructor  
  10. MonsterStrategyGangan::MonsterStrategyGangan()  
  11. {  
  12.     // do nothing...  
  13. }  
  14.   
  15. // destructor  
  16. MonsterStrategyGangan::~MonsterStrategyGangan()  
  17. {  
  18.     // do nothing...  
  19. }  
  20.   
  21. // move  
  22. void MonsterStrategyGangan::move(Monster& _monster)  
  23. {  
  24.     printf("inochi\n");  
  25. }  
  26. </stdio.h>  
①MonsterStrategyを継承しています。
②オーバーライドしたmove()メソッドです。

最後にmain.cppです。
  1. #include "Monster.h"  
  2. #include <stdio.h>  
  3.   
  4. void main(void)  
  5. {  
  6.     Monster monster;    //  モンスター生成  
  7.     monster.init();     //  初期化  
  8.     monster.move();     //  move  
  9.     monster.setCurrentStrategyType(MonsterStrategy::ST_GANGAN); //  戦略変更  
  10.     monster.move();     //  move  
  11.   
  12.     printf("hit any key...");  
  13.     while(getchar() == EOF){}  
  14. }  
  15. </stdio.h>  

以上でStrategyパターンの説明は終わりです。クラス数は少し多いですがそんなに難しいパターンではないはずです。
ソースコードはコピペで動かせるハズですので是非試してみてください。

0 件のコメント:

コメントを投稿