PHP行为型设计模式(三)

884 阅读2分钟

续上一篇:PHP行为型设计模式(二),本文介绍第三类行为型设计模式。

类的状态

  • 备忘录模式(Memento Pattern)
  • 状 态 模 式 (State Pattern)

PHP设计模式(十八)—备忘录模式(Memento Pattern)

备忘录模式 (Memento Pattern): 在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。又叫做快照模式(Snapshot Pattern)Token模式

(一)为什么需要备忘录模式

1,有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这时,使用备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。

2,本模式简化了发起人类。发起人不再需要管理和保存其内部状态的一个个版本,客户端可以自行管理他们所要的这些状态的版本。

(二)备忘录模式 UML图

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图

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行为型设计模式(四)介绍,欢迎大家评论指正


我最近的学习总结:


欢迎大家关注我的微信公众号 火风鼎