欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

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

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

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

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

          Gof類圖及解釋

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

          GoF類圖:

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

          代碼實現(xiàn):

          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;     } }

          原發(fā)器,也可以叫做發(fā)起人。它有一個內(nèi)部狀態(tài)(state),這個狀態(tài)可以在不同的情況下進行改變。當某一個事件發(fā)生時,需要將這個狀態(tài)恢復到原先的狀態(tài)。在這里,我們有一個CreateMemento()用于創(chuàng)建一個備忘錄(存檔),有一個SetMeneto()用于還原狀態(tài)(讀檔)。

          class Memento {     private $state;     public function SetState($state)     {         $this->state = $state;     }     public function GetState()     {         return $this->state;     } }

          備忘錄,非常簡單,就是用于記錄狀態(tài)。將這個狀態(tài)以對象的形式保存,就可以讓原發(fā)器非常方便地創(chuàng)建很多存檔用于記錄各種不同的狀態(tài)。

          class Caretaker {     private $memento;     public function SetMemento($memento)     {         $this->memento = $memento;     }     public function GetMemento()     {         return $this->memento;     } }

          負責人,也叫做管理者類,保存?zhèn)渫?,當需要的時候從這里取出備忘錄。它只負責保存,不能修改備忘錄。在復雜的應用中,可以將這里做成列表,就像游戲中可以選擇性的展現(xiàn)多條存檔記錄供玩家選擇。

          $o = new Originator(); $o->SetState('狀態(tài)1'); $o->ShowState();  // 保存狀態(tài) $c = new Caretaker(); $c->SetMemento($o->CreateMemento());  $o->SetState('狀態(tài)2'); $o->ShowState();  // 還原狀態(tài) $o->SetMeneto($c->GetMemento()); $o->ShowState();

          客戶端的調(diào)用中,我們的原發(fā)器初始化狀態(tài)后進行了保存,然后人為的更改了狀態(tài)。這時只需要通過負責人將狀態(tài)還原回來就可以了。

          • 備忘錄模式說白了就是讓一個外部類B來保存A的內(nèi)部狀態(tài),然后在適當?shù)臅r候可以方便的還原這個狀態(tài)。
          • 備忘錄模式的應用場景其實非常多,瀏覽器的回退、數(shù)據(jù)庫的備份還原、操作系統(tǒng)的備份還原、文檔的撤銷重做、棋牌游戲的悔棋等等
          • 這個模式能夠保持對原發(fā)器的封裝,也就是這些狀態(tài)需要對外部的對象隱藏,所以只能交給一個備忘錄對象來記錄
          • 狀態(tài)在原發(fā)器和備忘錄之間的拷貝可能帶來性能問題,特別是大型對象的復雜繁多的內(nèi)部狀態(tài),而且也會帶來一些編碼方面的漏洞,比如漏掉某些狀態(tài)

          Mac的時光機功能大家有了解過吧,可以將電腦恢復到某一時間點的狀態(tài)下。其實windows的ghost也是類似的功能。我們的手機操作系統(tǒng)上也決定開發(fā)這樣的一個功能。當我們點擊時光機備份時,將手機上所有的資料、數(shù)據(jù)、狀態(tài)信息都壓縮保存起來,如果用戶允許的話,我們將這個壓縮包上傳到我們的云服務器上避免占用用戶的手機內(nèi)存,否則就只能保存到用戶的手機內(nèi)存中了。當用戶的手機需要恢復到某個時間點,我們將所有的時光機備份列出,用戶只需要用手指輕輕一按就可以把手機系統(tǒng)狀態(tài)恢復到當時的樣子了,是不是非常方便??!

          完整代碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/17.memento/source/memento.php

          實例

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

          短信發(fā)送類圖

          一起聊聊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 = '未發(fā)送';         $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;     } }  // 模擬短信發(fā)送 $mList = []; $scList = []; for ($i = 0; $i < 10; $i++) {     $m = new Message('手機號' . $i, '內(nèi)容' . $i);     echo '初始狀態(tài):';     $m->Show();      // 保存初始信息     $sc = new StateContainer();     $sc->SetSaveState($m->CreateSaveSate());     $scList[] = $sc;      // 模擬短信發(fā)送,2發(fā)送成功,3發(fā)送失敗     $pushState = mt_rand(2, 3);     $m->SetState($pushState == 2 ? '發(fā)送成功' : '發(fā)送失敗');     echo '發(fā)布后狀態(tài):';     $m->Show();      $mList[] = $m; }  // 模擬另一個線程查找發(fā)送失敗的并把它們還原到未發(fā)送狀態(tài) sleep(2); foreach ($mList as $k => $m) {     if ($m->GetState() == '發(fā)送失敗') { // 如果是發(fā)送失敗的,還原狀態(tài)         $m->SetSaveState($scList[$k]->GetSaveState());     }     echo '查詢發(fā)布失敗后狀態(tài):';     $m->Show(); }

          說明

          • 短信類做為我們的原發(fā)器,在發(fā)送前就保存了當前的發(fā)送狀態(tài)
          • 隨機模擬短信發(fā)送,只有兩個狀態(tài),發(fā)送成功或者失敗,并改變原發(fā)器的狀態(tài)為成功或者失敗
          • 模擬另一個線程或者腳本對短信的發(fā)送狀態(tài)進行檢查,如果發(fā)現(xiàn)有失敗的,就將它重新改回未發(fā)送的狀態(tài)
          • 這里我們只是保存了發(fā)送狀態(tài)這一個字段,其他原發(fā)器的內(nèi)部屬性并沒有保存
          • 真實的場景下我們應該會有一個重試次數(shù)的限制,當超過這個次數(shù)后,狀態(tài)改為徹底的發(fā)送失敗,不再進行重試了

          原文地址:https://juejin.cn/post/6844903983555805192

          作者:硬核項目經(jīng)理

          推薦學習:《PHP視頻教程》

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號