您好,登錄后才能下訂單哦!
本篇內容主要講解“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();
客戶端的調用中,我們的原發器初始化狀態后進行了保存,然后人為的更改了狀態。這時只需要通過負責人將狀態還原回來就可以了。
備忘錄模式說白了就是讓一個外部類B來保存A的內部狀態,然后在適當的時候可以方便的還原這個狀態。
備忘錄模式的應用場景其實非常多,瀏覽器的回退、數據庫的備份還原、操作系統的備份還原、文檔的撤銷重做、棋牌游戲的悔棋等等
這個模式能夠保持對原發器的封裝,也就是這些狀態需要對外部的對象隱藏,所以只能交給一個備忘錄對象來記錄
狀態在原發器和備忘錄之間的拷貝可能帶來性能問題,特別是大型對象的復雜繁多的內部狀態,而且也會帶來一些編碼方面的漏洞,比如漏掉某些狀態
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(); }
說明
短信類做為我們的原發器,在發送前就保存了當前的發送狀態
隨機模擬短信發送,只有兩個狀態,發送成功或者失敗,并改變原發器的狀態為成功或者失敗
模擬另一個線程或者腳本對短信的發送狀態進行檢查,如果發現有失敗的,就將它重新改回未發送的狀態
這里我們只是保存了發送狀態這一個字段,其他原發器的內部屬性并沒有保存
真實的場景下我們應該會有一個重試次數的限制,當超過這個次數后,狀態改為徹底的發送失敗,不再進行重試了
到此,相信大家對“PHP中的備忘錄模式是干什么的”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。