1. 程式人生 > >PHP設計模式——狀態模式

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子類。

相關資料

參考文獻:

https://segmentfault.com/a/1190000006814615