Chatper 5 原型模式 核心思想是一個對象可以生成與自身相似的其他對象。 基類Monster,有一個抽象方法clone: 1 class Monster 2 { 3 public: 4 5 virtual ~Monster() {} 6 virtual Monster* clone() = 0 ...
Chatper 5 原型模式
核心思想是一個對象可以生成與自身相似的其他對象。
基類Monster,有一個抽象方法clone:
1 class Monster 2 { 3 public: 4 5 virtual ~Monster() {} 6 virtual Monster* clone() = 0; 7 8 // Other stuff... 9 };
子類的clone實現:
1 class Ghost : public Monster { 2 public: 3 4 Ghost(int health, int speed) 5 : health_(health), 6 speed_(speed) 7 {} 8 9 virtual Monster* clone() 10 { 11 return new Ghost(health_, speed_); 12 } 13 14 private: 15 int health_; 16 int speed_; 17 };
通用的Spawner類:
1 class Spawner 2 { 3 4 public: 5 Spawner(Monster* prototype) 6 : prototype_(prototype) 7 {} 8 9 Monster* spawnMonster() 10 { 11 return prototype_->clone(); 12 } 13 14 private: 15 Monster* prototype_; 16 };
這樣用:
1 Monster* ghostPrototype = new Ghost(15, 3); 2 Spawner* ghostSpawner = new Spawner(ghostPrototype); 3 Monster* newGhost = Spawner->spawnMonster();
生成器函數和孵化函數指針:
1 Monster* spawnGhost() 2 { 3 return new Ghost(); 4 } 5 typedef Monster* (*SpawnCallback)(); 6 7 class Spawner 8 { 9 public: 10 Spawner(SpawnCallback spawn) 11 : spawn_(spawn) 12 {} 13 14 Monster* spawnMonster() 15 { 16 return spawn_(); 17 } 18 19 private: 20 SpawnCallback spawn_; 21 22 };
這樣用:
1 Spawner* ghostSpawner = new Spawner(spawnGhost); 2 Monster* newGhost = ghostSpawner->spawnMonster();
Chatper 6 單例模式
確保一個類只有一個實例,併為其提供一個全局訪問入口。
1 class FileSystem 2 { 3 public: 4 static FileSystem& instance() 5 { 6 static FileSystem *instance = new FileSystem(); 7 return *instance; 8 } 9 10 private: 11 FileSystem() {} 12 13 };
- 延遲初始化
- C++11保證局部靜態變數的初始化只進行一次
- 多線程安全
- 私有構造函數
繼承單例(多平臺):
1 class FileSystem 2 { 3 public: 4 5 static FileSystem& instance(); 6 7 virtual ~FileSystem() {} 8 9 virtual char* readFile(char* path) = 0; 10 virtual void writeFile(char* path, char* contents) = 0; 11 12 protected: 13 FileSystem() {} 14 15 }; 16 17 class PS3FileSystem : public FileSystem 18 { 19 20 public: 21 virtual char* readFile(char* path) 22 { 23 // Use Sony file IO API... 24 } 25 26 virtual void writeFile(char* path, char* contents) 27 { 28 // Use sony file IO API... 29 } 30 }; 31 32 class WiiFileSystem : public FileSystem 33 { 34 35 public: 36 virtual char* readFile(char* path) 37 { 38 // Use Nintendo file IO API... 39 } 40 41 virtual void writeFile(char* path, char* contents) 42 { 43 // Use Nintendo file IO API... 44 } 45 46 };
Instance的編譯跳轉實現:
1 FileSystem& FileSystem::instance() 2 { 3 4 #if PLATFORM == PLAYSTATION3 5 static FileSystem *instance = new PS3FileSystem(); 6 #elif PLATFORM == WII 7 static FileSystem *instance = new WiiFileSystem(); 8 #endif 9 10 return *instance; 11 }
單例的缺陷:
- 全局變數,單例就是一個全局狀態,只是被封裝到了類中;
- 延遲初始化可能導致掉幀和卡頓,可能導致記憶體佈局碎片化。
通過將全局對象類包裝在現有類里來減少全局對象數量:
1 class Game 2 { 3 4 public: 5 static Game& instance() { return instance_; } 6 7 // Functions to set log_, et. al. ... 8 9 Log& getLog() { return *log_; } 10 11 FileSystem& getFileSystem() { return *fileSystem_; } 12 13 AudioPlayer& getAudioPlayer() { return *audioPlayer_; } 14 15 private: 16 static Game instance_; 17 Log *log_; 18 FileSystem *fileSystem_; 19 AudioPlayer *audioPlayer_; 20 21 }; 22 23 Game::instance().getAudioPlayer().play(VERY_LOUD_BANG);
Chatper 7 狀態模式
允許一個對象在其內部狀態改變時改變自身的行為,對象看起來好像是在修改自身類。
複雜的分支和可變的狀態是兩種最容易出錯的代碼。
狀態、輸入和轉換:
1. 擁有一組數目較小的狀態,可以在這組狀態之間切換;
2. 同一時刻只能處於一種狀態;
3. 響應用戶輸入和游戲事件
定義一個介面,enter函數定義一些進入狀態時的處理,exit函數定義一些狀態改變前的處理:
1 class HeroineState 2 { 3 4 public: 5 virtual ~HeroineState() {} 6 virtual void handleInput(Heroine& heroine, Input input) {} 7 virtual void update(Heroine& heroine) {} 8 9 virtual void enter(Heroine& heroine) {} 10 virtual void exit(Heroine& heroine) {} 11 12 };
每一個狀態都繼承這個狀態介面:
1 class DuckingState : public HeroineState 2 { 3 4 public: 5 DuckingState() 6 : chargeTime_(0) 7 {} 8 9 virtual void handleInput(Heroine& heroine, Input input) { 10 if (input == RELEASE_DOWN) 11 { 12 // Change to standing state... 13 heroine.setGraphics(IMAGE_STAND); 14 } 15 } 16 17 virtual void update(Heroine& heroine) { 18 chargeTime_++; 19 if (chargeTime_ > MAX_CHARGE) 20 { 21 heroine.superBomb(); 22 } 23 } 24 25 private: 26 int chargeTime_; 27 28 };
主角類中有一個指針指向當前狀態:
1 class Heroine 2 { 3 4 public: 5 virtual void handleInput(Input input) 6 { 7 state_->handleInput(*this, input); 8 } 9 10 virtual void update() 11 { 12 state_->update(*this); 13 } 14 15 // Other methods... 16 17 private: 18 HeroineState* state_; 19 20 };
靜態狀態(省CPU省記憶體):
1 class HeroineState 2 { 3 4 public: 5 static StandingState standing; 6 static DuckingState ducking; 7 static JumpingState jumping; 8 static DivingState diving; 9 10 // Other code... 11 }; 12 13 if (input == PRESS_B) 14 { 15 heroine.state_ = &HeroineState::jumping; 16 heroine.setGraphics(IMAGE_JUMP); 17 }
實例化狀態(handleInput方法返回後刪除原狀態):
1 void Heroine::handleInput(Input input) 2 { 3 HeroineState* state = state_->handleInput(*this, input); 4 if (state != NULL) 5 { 6 delete state_; 7 state_ = state; 8 9 // Call the enter action on the new state. 10 state_->enter(*this); 11 } 12 } 13 14 HeroineState* StandingState::handleInput( 15 Heroine& heroine, Input input) 16 { 17 if (input == PRESS_DOWN) 18 { 19 // Other code... 20 return new DuckingState(); 21 } 22 23 // Stay in this state. 24 return NULL; 25 }
併發狀態機(當兩種狀態沒什麼關係時):
1 class Heroine 2 { 3 4 // Other code... 5 6 private: 7 HeroineState* state_; 8 HeroineState* equipment_; 9 10 }; 11 12 void Heroine::handleInput(Input input) 13 { 14 state_->handleInput(*this, input); 15 equipment_->handleInput(*this, input); 16 }
如果兩種狀態有一些聯繫(不能太多),需要對某些狀態處理進行干預,可以做一些簡單的if判斷並特殊處理下。
層次狀態機:
一個狀態有父狀態,如果子狀態不處理就交給他的父狀態處理。用來處理可能包含的大量相似狀態。
1 class OnGroundState : public HeroineState 2 { 3 4 public: 5 virtual void handleInput(Heroine& heroine, Input input) 6 { 7 if (input == PRESS_B) 8 { 9 // Jump... 10 } 11 else if (input == PRESS_DOWN) 12 { 13 // Duck... 14 } 15 } 16 }; 17 18 class DuckingState : public OnGroundState 19 { 20 21 public: 22 virtual void handleInput(Heroine& heroine, Input input) 23 { 24 if (input == RELEASE_DOWN) 25 { 26 // Stand up... 27 } 28 else 29 { 30 // Didn't handle input, so walk up hierarchy. 31 OnGroundState::handleInput(heroine, input); 32 } 33 } 34 };
下推自動機:
開火時push Firing,結束後pop掉開火狀態,狀態機自動返回開火前的狀態。