備忘錄模式 (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肯定是不一樣的。