PHP行為型設計模式(三)

fangle發表於2017-05-23

續上一篇:PHP行為型設計模式(二),本文介紹第三類行為型設計模式。

類的狀態

  • 備忘錄模式(Memento Pattern)
  • 狀 態 模 式 (State Pattern)

PHP設計模式(十八)—備忘錄模式(Memento Pattern)

備忘錄模式 (Memento Pattern): 在不破壞封閉的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可將該物件恢復到原先儲存的狀態。又叫做快照模式(Snapshot Pattern)Token模式

(一)為什麼需要備忘錄模式

1,有時一些發起人物件的內部資訊必須儲存在發起人物件以外的地方,但是必須要由發起人物件自己讀取,這時,使用備忘錄模式可以把複雜的發起人內部資訊對其他的物件遮蔽起來,從而可以恰當地保持封裝的邊界。

2,本模式簡化了發起人類。發起人不再需要管理和儲存其內部狀態的一個個版本,客戶端可以自行管理他們所要的這些狀態的版本。

(二)備忘錄模式 UML圖

PHP行為型設計模式(三)
Memento Pattern

(三)簡單例項

備忘錄模式往簡單了說,就是打副本。這裡我們給出一個備忘錄模式的小例子,備份一個遊戲角色,也就是發起者的初始狀態,並恢復。

<?php
//發起人,所需備份者
class Originator{
    //內部狀態
    private $state;
    //設定狀態
    public function setState($state){
        $this->state = $state ;
    }
    //檢視狀態
    public function getState(){
        echo $this->state,PHP_EOL;
    }
    //建立一個備份錄
    public function createMemento(){
        return new Memento($this->state);
    }
    //恢復一個備份
    public function restoreMemento(Memento $memento){
        $this->state = $memento->getState();
    }
}
//備忘錄角色
class Memento{
    private $state; //用於存放發起人備份時的狀態
    public function __construct($state){
        $this->state = $state;
    }
    public function getState(){
        return $this->state;
    }
}
//備忘錄管理者
class Caretaker{
    private $menento;
    //存檔備忘錄
    public function setMemento(Memento $memento){
        $this->memento = $memento;
    }
    //取出備忘錄
    public function getMemento(){
        return $this->memento;
    }
}

//例項化發起人 假如是個遊戲角色
$role = new Originator;
//設定狀態 滿血
$role->setState('滿血');
//備份
//建立備份錄管理者
$caretaker = new Caretaker;
//建立備份
$caretaker->setMemento($role->createMemento());
//狀態更改
$role->setState('死亡');
$role->getState();
//恢復備份
$role->restoreMemento($caretaker->getMemento());
//重新檢視狀態
$role->getState();複製程式碼

可能最後那段恢復備份的程式碼有點繞,這是因為我們引入了備份管理者。其實如果對於只有一個備份,那麼我們也可以不用備份管理者。而備份管理者存在的好處,當然是管理多個備份了。如果對於多個備份,我們可以把備份管理者的memento屬性改為陣列變數,就可以存放多個備份了。

其實備份在原型模式我們也提過,我們完全可以通過clone關鍵字來備份,但是備忘錄模式相對於原型模式更精簡,可能有些時候我們只想備份的就只有這一個屬性呢。而且從本質上說備忘錄模式恢復備份後還是原來那個物件,而原型模式就不一定了。如果原型模式恢復備份是直接使用clone出來的物件副本,那麼其實它就不算原來那個物件了,雖然它和被clone的物件幾乎一模一樣,使用無差別,但是對於var_dump,它的object#id肯定是不一樣的。


PHP設計模式(十九)—狀態模式(State Pattern)

狀態模式 (State Pattern) :允許一個物件在其內部狀態改變時改變它的行為,讓不同狀態的物件看起來似乎修改了它的類,或者說是看起來不是來自同一個類。

(一)為什麼需要狀態模式

1,將所有與某個狀態有關的行為放到一個類中,並且可以方便地增加新的狀態,只需要改變物件狀態即可改變物件的行為。

2,本模式簡化了發起人類。發起人不再需要管理和儲存其內部狀態的一個個版本,客戶端可以自行管理他們所要的這些狀態的版本。

(二)狀態模式 UML圖

PHP行為型設計模式(三)
State Pattern

(三)簡單例項

狀態模式一個最妙的應用就是通過變化狀態擁有不同的能力。比如我們以水為例,水如果是固態,那麼它就能融化成液態,如果是液態那麼它就能蒸發成氣態,而氣態也能凝華成固態。現在就讓我們用程式來模擬這個過程。

<?php
//抽象狀態類
abstract class State{
  abstract function handle();
}
//固態
class Solid extends State{
    public function handle(){
        echo '固態 =>融化 =>液態轉化中'.PHP_EOL;
    }
}
class Liquid extends State{
    public function handle(){
        echo '液態 =>蒸發 =>氣態轉化中'.PHP_EOL;
    }
}
class Gas extends State{
    public function handle(){
        echo '氣態 =>凝華 =>固態轉化中'.PHP_EOL;
    }
}
//context環境類 -----water
class Water{
  protected $states = array();
  protected $current=0;
  public function __construct()
  {
      $this->states[]=new Solid;
      $this->states[]=new Liquid;
      $this->states[]=new Gas;
  }
  //水的變化
  public function change(){
    //告知當前狀態
    echo '當前所處狀態'.get_Class($this->states[$this->current]).PHP_EOL;
    //當前狀態能力
    $this->states[$this->current]->handle();
    //狀態變化
    $this->changeState();
  }
  //狀態變化
  public function changeState()
  {
      $this->current++ == 2 && $this->current = 0;
  }
}



//例項化具體環境角色-----水
$water = new Water;
//水的能力變化   ---與它的狀態相關
$water->change();
$water->change();
$water->change();
$water->change();複製程式碼

當然我們這裡只是一個簡單的示例,你完全可以讓一個狀態有多個能力,或者通過給water給一個對外的介面,通過傳參使其轉化為你指定的狀態。


上一篇::PHP行為型設計模式(二)

感謝閱讀,由於筆者也是初學設計模式,能力有限,文章不可避免地有失偏頗
後續更新 PHP行為型設計模式(四)介紹,歡迎大家評論指正


我最近的學習總結:


PHP行為型設計模式(三)
歡迎大家關注我的微信公眾號 火風鼎

相關文章