PHP設計模式——狀態模式
前言
狀態設計模式是Gof提出的最吸引人的模式之一,也是一種最有用的模式。遊戲通常就採用狀態模式,因為遊戲中的物件往往會非常頻繁地改變狀態。狀態模式的作用就是允許物件在狀態改變時改變其行為。還有很多其他模擬應用(不一定是遊戲)也依賴於狀態模式。本文將會談到並舉例說明。
按照傳統思維,如果有多個狀態的話一般就是用if、else if、switch處理了,但是這類的程式碼看起來極其不美觀,最重要的是沒什麼拓展性,維護性,複用性,還會出現“牽一髮而動全身”的情況。如果把這些狀態封裝起來,就可以減少大量的判斷,那麼就要用狀態模式了。
需求分析
1、程式碼遵循可拓展性強,可維護性強,複用性強,杜絕”牽一髮而動全身”的情況。
2、減少使用大量的if、else if、switch判斷。
核心程式碼
1、Work.php(它定義了時間程式需要的介面並維護一個具體狀態角色的例項,將與狀態相關的操作委託給當前的具體物件來處理。)
<?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); } }
2、IState.php(定義一個介面以封裝使用上下文環境的的一個特定狀態相關的行為。)
<?php
namespace common\status;
//狀態介面
interface IState
{
public function WriteCode($w);
}
3、EarlyMorning.php(實現抽象狀態定義的介面。)
//早晨工作狀態 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、例如:在原來的應用中增加個“半夜的狀態”。
1.1、在原夜裡工作狀態類增加個if判斷,符合條件時呼叫半夜的工作狀態。
<?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.2、新增一個半夜工作狀態類,裡面寫要執行的行為。
<?php
namespace common\status;
use Yii;
use common\status\IState;
//半夜工作狀態
class Midnight implements IState
{
public function WriteCode($w)
{
return Yii::t('yii','midnight');
}
}
怎麼樣,增加一個狀態是不是很簡單?拓展性非常好。
提醒注意
1、實現狀態介面類中的$w->WriteCode()必須要return返回,否則呼叫客戶端程式碼的時候無法賦值給$call,會直接echo輸出。
2、實現狀態介面類中的public function WriteCode($w)方法裡的$w物件類應該是Work物件,不能是當前類的物件。
總結分析
1、優點
1.1、狀態模式將與特定狀態相關的行為區域性化,並且將不同狀態的行為分割開來。
1.2、所有狀態相關的程式碼都存在於某個ConcereteState中,所以通過定義新的子類很容易地增加新的狀態和轉換。
1.3、狀態模式通過把各種狀態轉移邏輯分不到State的子類之間,來減少相互間的依賴。
2、缺點
2.1、導致較多的ConcreteState子類。
相關資料
參考文獻: