今天想跟大家分享的設計模式叫做”State Pattern” 狀態模式,最近在工作上遇到一個案例,我覺得就非常適合使用這個模式去重構,當我今天看到在某個物件中,有過多的if….else if…..or Switch case…或許你可以試著思考是否可以使用State Pattern去把過多的條件敘述簡化掉,在我遇到的案例中,我發現了像下列的程式碼:
1: void Update()2: {3: switch (PlayerMode)4: {5: case : Attack6: //....7: break;8:9: case : Idle10: //....11: break;12:13: case : Damage14: //....15: break;16:17: case : Move18: //....19: break;20:21: case : Jump22: //....23: break;24:25: case : JumpAttack26: //....27: break;28:29: case : Run30: //....31: break;32: //.....................33:34: }35: }
這時候我們會發現所有的條件判斷可能都在這一個Update Function內,當我們需要增加新的狀態的時候,我們就必須增加新的程式碼在這個Function裡面,然後可能每個Switch case判斷敘述中,又會加很多在該狀態才會特有的敘述,這些對程式碼的閱讀以後後續的維護,都相對的來的複雜了些,所以今天我們來使用”State Pattern”
State Pattern的定義:
允許物件隨著內在的狀態改變而改變行為,好像物件的類別改變了一樣。
這句話是什麼意思呢,還記得我們上一篇談到的策略模式嗎。當我們需要改變他的行為的時候就去替換該行為的演算法,在State Pattern中,也是運用一樣的概念,根據狀態改變,而改變行為的演算法。
類別圖:
以上圖來看,狀態模式允許一個物件能夠根據內部狀態的不同而有不同的行為。
藉由將每個狀態都封裝成各自的物件,以後任何改變的需求都將只會影響到局部。
所以,以案例來看,我們的程式碼可能就會變成:
類似這樣的概念,我們還可以使用一個類別,去管理你所有的State,可能會有一個list or Vector 容器,去做儲存所有State,然後再切換的時候根據目前的狀況,去更換所使用的類別,不過這些不是這邊討論的範圍。1: class PlayerState2: {3: public:4: PlayerState();5: virtual ~PlayerState();6: virtual void Update();7: }8:9: class Attatck : public PlayerState10: {11: public:12: Attatck ();13: virtual Attatck ();14: virtual void Update();15: }16:17: class Idle: public PlayerState18: {19: public:20: Idle: ();21: virtual Idle: ();22: virtual void Update();23: }24: ///.........25: ///..........26: ///..........27:28: void Update()29: {30: m_pCurrentState->Update()31: }32:33: void ChangeState(PlayerMode)34: {35: switch case:36: {37: case Attatk:38: m_pCurrentState = m_pAttackState;39: break;40: }41: }
狀態模式與策略模式:
剛剛我們有談到,狀態模式跟策略模式,都是根據需求不同,去切換封裝的演算法。但是他們還是有些些微的差異。
以狀態模式而言,我們將一群行為封裝在狀態物件中,context的行為隨時可以委派到那些狀態物件的其中之一。隨著時間的改變,目前狀態將持續改變所有狀態物件的行為,反映出context內部的狀態,因此,context的行為也跟著改變,但是context的user對於狀態物件所知不多,
以策略模式而言,user通常主動指定context所要合成的策略物件為何者。現在,固然策略模式具有彈性,能夠動態在執行期做改變,但對於某個context來說,經常都只有一個最適當的策略物件。
但是狀態模式跟策略模式都有一樣的缺點,當你的State越來越多,相對的你的class就會越來越多,這是因為你需要分割封裝的演算法變多了,相對的class就多了。
沒有留言:
張貼留言