在先前的文章《深入淺析PHP中的建造者模式》中我們介紹了PHP中的建造者模式,以下這篇文章帶大家了解一下PHP設計模式中的備忘錄模式。
備忘錄,這個名字其實已經很形象的解釋了它的作用。典型的例子就是我們原來玩硬碟遊戲時的存檔功能。當你對即將面對的大BOSS有所顧慮時,一般都會先保存一次進度存檔。如果挑戰失敗了,直接讀取存檔就可以恢復到挑戰BOSS前的狀態,然後你就開開心心的再去練一會級回來解決這個大BOSS就好了。不過,為了以防萬一,在挑戰BOSS之前就先存檔總是好的。另外一個例子就是我們碼農們天天要用到的程式碼管理工具Git或Svn了。每次的提交都像是存檔備份,當新程式碼出現問題的時候,直接回溯恢復就行了。這些,都是備忘錄模式的典型應用,以下就一起來看看這個模式吧。
GoF定義:在不破壞封裝性的前提下,捕捉一個物件的內部狀態,並在該物件之外保存這個狀態。這樣以後就可將該物件還原到原先儲存的狀態
GoF類別圖:
程式碼實作:
class Originator { private $state; public function SetMeneto(Memento $m) { $this->state = $m->GetState(); } public function CreateMemento() { $m = new Memento(); $m->SetState($this->state); return $m; } public function SetState($state) { $this->state = $state; } public function ShowState() { echo $this->state, PHP_EOL; } }
原發器,也可以叫做發起人。它有一個內部狀態(state),這個狀態可以在不同的情況下進行改變。當某一個事件發生時,需要將這個狀態恢復到原先的狀態。在這裡,我們有一個CreateMemento()用於建立一個備忘錄(存檔),有一個SetMeneto()用於還原狀態(讀檔)。
class Memento { private $state; public function SetState($state) { $this->state = $state; } public function GetState() { return $this->state; } }
備忘錄,非常簡單,就是用來記錄狀態。將這個狀態以物件的形式保存,就可以讓原發器非常方便地建立許多存檔用來記錄各種不同的狀態。
class Caretaker { private $memento; public function SetMemento($memento) { $this->memento = $memento; } public function GetMemento() { return $this->memento; } }
負責人,也叫做管理者類,保存備忘錄,當需要的時候從這裡取出備忘錄。它只負責保存,不能修改備忘錄。在複雜的應用中,可以將這裡做成列表,就像遊戲中可以選擇性的展現多條存檔記錄供玩家選擇。
$o = new Originator(); $o->SetState('状态1'); $o->ShowState(); // 保存状态 $c = new Caretaker(); $c->SetMemento($o->CreateMemento()); $o->SetState('状态2'); $o->ShowState(); // 还原状态 $o->SetMeneto($c->GetMemento()); $o->ShowState();
客戶端的呼叫中,我們的原發器初始化狀態後進行了保存,然後人為的更改了狀態。這時只需要透過負責人將狀態還原回來就可以了。
##Mac的時光機功能大家有了解吧,可以將電腦恢復到某個時間點的狀態。其實windows的ghost也是類似的功能。我們的手機作業系統上也決定開發這樣的一個功能。當我們點擊時光機備份時,將手機上所有的資料、數據、狀態資訊都壓縮保存起來,如果用戶允許的話,我們將這個壓縮包上傳到我們的雲端伺服器上避免佔用用戶的手機內存,否則就只能儲存到用戶的手機內存了。當用戶的手機需要恢復到某個時間點,我們將所有的時光機備份列出,用戶只需要用手指輕輕一按就可以把手機系統狀態恢復到當時的樣子了,是不是非常方便! !
完整程式碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/17.memento/source/memento.php
簡訊發送類別圖
#完整原始碼:https://github.com/zhangyue0503/designpatterns-php /blob/master/17.memento/source/memento-message.php
<?php class Message { private $content; private $to; private $state; private $time; public function __construct($to, $content) { $this->to = $to; $this->content = $content; $this->state = '未发送'; $this->time = time(); } public function Show() { echo $this->to, '---', $this->content, '---', $this->time, '---', $this->state, PHP_EOL; } public function CreateSaveSate() { $ss = new SaveState(); $ss->SetState($this->state); return $ss; } public function SetSaveState($ss) { if ($this->state != $ss->GetState()) { $this->time = time(); } $this->state = $ss->GetState(); } public function SetState($state) { $this->state = $state; } public function GetState() { return $this->state; } } class SaveState { private $state; public function SetState($state) { $this->state = $state; } public function GetState() { return $this->state; } } class StateContainer { private $ss; public function SetSaveState($ss) { $this->ss = $ss; } public function GetSaveState() { return $this->ss; } } // 模拟短信发送 $mList = []; $scList = []; for ($i = 0; $i < 10; $i++) { $m = new Message('手机号' . $i, '内容' . $i); echo '初始状态:'; $m->Show(); // 保存初始信息 $sc = new StateContainer(); $sc->SetSaveState($m->CreateSaveSate()); $scList[] = $sc; // 模拟短信发送,2发送成功,3发送失败 $pushState = mt_rand(2, 3); $m->SetState($pushState == 2 ? '发送成功' : '发送失败'); echo '发布后状态:'; $m->Show(); $mList[] = $m; } // 模拟另一个线程查找发送失败的并把它们还原到未发送状态 sleep(2); foreach ($mList as $k => $m) { if ($m->GetState() == '发送失败') { // 如果是发送失败的,还原状态 $m->SetSaveState($scList[$k]->GetSaveState()); } echo '查询发布失败后状态:'; $m->Show(); }
说明
原文地址:https://juejin.cn/post/6844903983555805192
作者:硬核项目经理
推荐学习:《PHP视频教程》
以上是一起聊聊PHP中的備忘錄模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!