狀態設計模式是Gof提出的最吸引人的模式之一,也是一種最有用的模式。遊戲一般就採用狀態模式,由於遊戲中的對象每每會很是頻繁地改變狀態。狀態模式的做用就是容許對象在狀態改變時改變其行爲。還有不少其餘模擬應用(不必定是遊戲)也依賴於狀態模式。本文將會談到並舉例說明。
按照傳統思惟,若是有多個狀態的話通常就是用if、else if、switch處理了,可是這類的代碼看起來極其不美觀,最重要的是沒什麼拓展性,維護性,複用性,還會出現「牽一髮而動全身」的狀況。若是把這些狀態封裝起來,就能夠減小大量的判斷,那麼就要用狀態模式了。php
一、代碼遵循可拓展性強,可維護性強,複用性強,杜絕」牽一髮而動全身」的狀況。
二、減小使用大量的if、else if、switch判斷。設計模式
一、Work.php(它定義了時間程序須要的接口並維護一個具體狀態角色的實例,將與狀態相關的操做委託給當前的具體對象來處理。)yii
<?php namespace common\status; //工做狀態 class Work { private $current; public $hour; public function __construct() { $this->current = new EarlyMorning(); } //設置狀態 public function SetState($s) { $this->current = $s; } public function WriteCode() { return $this->current->WriteCode($this); } }
二、IState.php(定義一個接口以封裝使用上下文環境的的一個特定狀態相關的行爲。)this
<?php namespace common\status; //狀態接口 interface IState { public function WriteCode($w); }
三、EarlyMorning.php(實現抽象狀態定義的接口。)spa
//早晨工做狀態 class EarlyMorning implements IState { public function WriteCode($w) { if($w->hour<6) { return Yii::t('yii','Good Early morning'); }else{ $w->SetState(new GoodMorning()); return $w->WriteCode(); //注意:這裏必須都要return返回,不然調用客戶端代碼的時候沒法賦值給$call。 } } } //早上工做狀態 class GoodMorning implements IState { public function WriteCode($w) { if($w->hour<9) { return Yii::t('yii','Good morning'); }else{ $w->SetState(new GoodForenoon()); return $w->WriteCode(); } } } //上午工做狀態 class GoodForenoon implements IState { public function WriteCode($w) { if($w->hour<12) { return Yii::t('yii','Good forenoon'); }else{ $w->SetState(new GoodNoon()); return $w->WriteCode(); } } } //中午工做狀態 class GoodNoon implements IState { public function WriteCode($w) { if($w->hour<14) { return Yii::t('yii','Good noon'); }else{ $w->SetState(new GoodAfternoon()); return $w->WriteCode(); } } } //下午工做狀態 class GoodAfternoon implements IState { public function WriteCode($w) { if($w->hour<17) { return Yii::t('yii','Good afternoon'); }else{ $w->SetState(new GoodDusk()); return $w->WriteCode(); } } } //傍晚工做狀態 class GoodDusk implements IState { public function WriteCode($w) { if($w->hour<19) { return Yii::t('yii','Good dusk'); }else{ $w->SetState(new GoodNight()); return $w->WriteCode(); } } } //晚上工做狀態 class GoodNight implements IState { public function WriteCode($w) { if($w->hour<22) { return Yii::t('yii','Good night'); }else{ $w->SetState(new GoodAtNight()); return $w->WriteCode(); } } } //夜裏工做狀態 class GoodAtNight implements IState { public function WriteCode($w) { return Yii::t('yii','Good at night'); } }
<?php use common\status\Work; //問候語 $emergWork = new Work(); $emergWork->hour = date("H"); $call=$emergWork->WriteCode();
一、例如:在原來的應用中增長個「半夜的狀態」。
1.一、在原夜裏工做狀態類增長個if判斷,符合條件時調用半夜的工做狀態。.net
<?php namespace common\status; use Yii; use common\status\IState; //夜裏工做狀態 class GoodAtNight implements IState { public function WriteCode($w) { if($w->hour<23) { return Yii::t('yii','Good at night'); }else{ $w->SetState(new Midnight()); return $w->WriteCode(); } } }
1.二、新增一個半夜工做狀態類,裏面寫要執行的行爲。設計
<?php namespace common\status; use Yii; use common\status\IState; //半夜工做狀態 class Midnight implements IState { public function WriteCode($w) { return Yii::t('yii','midnight'); } }
怎麼樣,增長一個狀態是否是很簡單?拓展性很是好。code
一、實現狀態接口類中的$w->WriteCode()必需要return返回,不然調用客戶端代碼的時候沒法賦值給$call,會直接echo輸出。
二、實現狀態接口類中的public function WriteCode($w)方法裏的$w對象類應該是Work對象,不能是當前類的對象。對象
一、優勢
1.一、狀態模式將與特定狀態相關的行爲局部化,而且將不一樣狀態的行爲分割開來。
1.二、全部狀態相關的代碼都存在於某個ConcereteState中,因此經過定義新的子類很容易地增長新的狀態和轉換。
1.三、狀態模式經過把各類狀態轉移邏輯分不到State的子類之間,來減小相互間的依賴。
二、缺點
2.一、致使較多的ConcreteState子類。blog