狀態模式
當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。
狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於復雜時的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把復雜的判斷邏輯簡化。
將與特點狀態相關的行為局部化,並且將不同狀態的行為分割開來!
UML:
代碼實現:
以前很喜歡玩war3里面的國家對抗,是一個建造類游戲。里面的建築在不同的時候有不同的狀態,例如兵營在產兵的時候會發白光,
受傷的時候會着火,建造的時候有建築特效。兵營在建造沒完成的時候不能升級和產兵,升級的時候不能產兵,受傷着火了也能繼續產兵或升級。
假設這些建築的狀態和表現為:建造-建造特效、受傷-受傷着火、升級-升級藍光、生成-生產白光、修復-修復綠光。
實現各種狀態代碼state.h:
1 #ifndef STATE_H 2 #define STATE_H 3 #include <iostream> 4 using namespace std; 5 6 class absState{ 7 public: 8 virtual void show() = 0; 9 }; 10 11 class buildingState:public absState{ 12 public: 13 virtual void show() 14 { 15 cout<<"建造特效 "; 16 } 17 }; 18 19 class fireState:public absState{ 20 public: 21 virtual void show() 22 { 23 cout<<"受傷着火 "; 24 } 25 }; 26 27 class productionState:public absState{ 28 public: 29 virtual void show() 30 { 31 cout<<"生產白光 "; 32 } 33 }; 34 35 class upGradeState:public absState 36 { 37 public: 38 virtual void show() 39 { 40 cout<<"升級藍光 "; 41 } 42 }; 43 44 class repairState:public absState 45 { 46 public: 47 virtual void show() 48 { 49 cout<<"修復綠光 "; 50 } 51 }; 52 #endif
建築實現代碼building.h:
1 #ifndef BUILDING_H 2 #define BUILDING_H 3 #include "state.h" 4 5 #include <map> 6 #include <iostream> 7 using namespace std; 8 9 enum StateType 10 { 11 BUILDING, INJURED, REPAIR, UPGRADE, PRODUCTION 12 }; 13 14 class absBuilding 15 { 16 public: 17 absBuilding(char* name):mName(name){} 18 virtual void show() 19 { 20 cout<<mName<<"表現:"<<endl; 21 map<StateType, absState*>::iterator beg = mStates.begin(); 22 for ( ; beg != mStates.end(); beg++) 23 { 24 beg->second->show(); 25 } 26 cout<<endl; 27 }; 28 void eraseState(StateType type) //實現刪除一個特效 29 { 30 auto result = mStates.find(type); 31 if(result != mStates.end()) 32 mStates.erase(result); 33 } 34 protected: 35 char* mName; 36 map<StateType, absState*> mStates; 37 }; 38 39 class concreteBuilding:public absBuilding 40 { 41 public: 42 concreteBuilding(char* name):absBuilding(name) 43 { 44 mStates[BUILDING] = new buildingState(); 45 } 46 void upGrade() 47 { 48 auto result = mStates.find(UPGRADE); 49 if(result == mStates.end()) 50 { 51 mStates[UPGRADE] = new upGradeState(); 52 } 53 eraseState(BUILDING); //升級的時候必須是建造過程已經結束,所以需要刪掉“建築”狀態 54 eraseState(PRODUCTION); //升級的時候不能進行生產 55 } 56 void production() 57 { 58 auto result = mStates.find(PRODUCTION); 59 if(result == mStates.end()) 60 { 61 mStates[PRODUCTION] = new upGradeState(); 62 } 63 eraseState(BUILDING); //生產的時候必須已經建造完成 64 eraseState(UPGRADE); //生產的時候不能升級 65 } 66 void injured() 67 { 68 auto result = mStates.find(INJURED); 69 if(result == mStates.end()) 70 { 71 mStates[INJURED] = new fireState(); 72 }74 } 75 void repair() 76 { 77 auto injuredVal = mStates.find(INJURED); 78 if(injuredVal == mStates.end()) 79 return; 80 auto result = mStates.find(REPAIR); 81 if(result == mStates.end()) 82 { 83 mStates[REPAIR] = new repairState(); 84 }86 } 87 }; 88 89 #endif
客戶端代碼main.cpp:
1 #include <iostream> 2 #include "tank.h" 3 #include "building.h" 4 5 using namespace std; 6 class SiegeTank; 7 8 void main() 9 { 10 concreteBuilding cb("兵營"); 11 cb.production(); 12 cb.injured(); 13 cb.repair(); 14 cb.show(); 15 return; 16 }
結果: