站長資訊網
        最全最豐富的資訊網站

        一起聊聊PHP中的備忘錄模式

        在之前的文章《深入淺析PHP中的建造者模式》中我們介紹了PHP中的建造者模式,下面本篇文章帶大家了解一下PHP設計模式中的備忘錄模式。

        一起聊聊PHP中的備忘錄模式

        備忘錄,這個名字其實就已經很形象的解釋了它的作用。典型的例子就是我們原來玩硬盤游戲時的存檔功能。當你對即將面對的大BOSS有所顧慮時,一般都會先保存一次進度存檔。如果挑戰失敗了,直接讀取存檔就可以恢復到挑戰BOSS前的狀態,然后你就開開心心的再去練一會級回來解決這個大BOSS就好了。不過,為了以防萬一,在挑戰BOSS之前存個檔總是好的。另外一個例子就是我們碼農們天天要用到的代碼管理工具Git或者Svn了。每次的提交都像是一次存檔備份,當新代碼出現問題的時候,直接回滾恢復就行了。這些,都是備忘錄模式的典型應用,下面就一起來看看這個模式吧。

        Gof類圖及解釋

        GoF定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到原先保存的狀態

        GoF類圖:

        一起聊聊PHP中的備忘錄模式

        代碼實現:

        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

        實例

        這次又回到短信發送的例子上來。通常我們做短信或者郵件發送這些功能時,會有一個隊列從數據庫或者緩存中讀取要發送的內容進行發送,如果成功了就不管了,如果失敗了會將短信的狀態改成失敗或者重發。在這里,我們直接將它改回到之前未發送的狀態然后等待下次發送的隊列再次執行發送。

        短信發送類圖

        一起聊聊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視頻教程》

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 精品综合久久久久久97超人| 国产精品女人呻吟在线观看| 91精品国产综合久久久久久 | 久久精品国产亚洲7777| 91麻豆精品国产自产在线观看亚洲| 久久久无码精品午夜| 2022国产精品最新在线| 99视频精品全部在线观看| 亚洲国产小视频精品久久久三级 | 国产在线精品一区二区不卡| 亚洲一区二区精品视频| 精品91自产拍在线观看二区| 精品国产一区二区三区久久| 精品熟女少妇a∨免费久久| 亚洲国产精品成人久久蜜臀 | 国产三级国产精品国产普男人| 久久99国产精品一区二区| 香蕉久久夜色精品国产小说| 国产精品无码午夜福利| 亚洲处破女AV日韩精品| 日本精品少妇一区二区三区| 一本久久a久久精品综合夜夜| 97精品国产手机| 久久香蕉国产线看观看精品yw| 少妇亚洲免费精品| 久久精品18| 国产午夜精品一区二区| 国产韩国精品一区二区三区| 午夜精品美女写真福利| 老司机69精品成免费视频| 99热国内精品| 精品国产福利第一区二区三区| 国产精品va无码一区二区| 国产亚洲欧美精品永久| 精品国产三级a∨在线| 久久国产亚洲精品无码| 久久亚洲精精品中文字幕| 老司机亚洲精品影院| 久久久久久九九99精品 | 国产国产成人久久精品| 国产精品日日摸夜夜添夜夜添1国产精品va欧美精 |