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

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

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

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

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

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

          Gof類圖及解釋

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

          GoF類圖:

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

          代碼實(shí)現(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ā)起人。它有一個(gè)內(nèi)部狀態(tài)(state),這個(gè)狀態(tài)可以在不同的情況下進(jìn)行改變。當(dāng)某一個(gè)事件發(fā)生時(shí),需要將這個(gè)狀態(tài)恢復(fù)到原先的狀態(tài)。在這里,我們有一個(gè)CreateMemento()用于創(chuàng)建一個(gè)備忘錄(存檔),有一個(gè)SetMeneto()用于還原狀態(tài)(讀檔)。

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

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

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

          負(fù)責(zé)人,也叫做管理者類,保存?zhèn)渫洠?dāng)需要的時(shí)候從這里取出備忘錄。它只負(fù)責(zé)保存,不能修改備忘錄。在復(fù)雜的應(yīng)用中,可以將這里做成列表,就像游戲中可以選擇性的展現(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)后進(jìn)行了保存,然后人為的更改了狀態(tài)。這時(shí)只需要通過(guò)負(fù)責(zé)人將狀態(tài)還原回來(lái)就可以了。

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

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

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

          實(shí)例

          這次又回到短信發(fā)送的例子上來(lái)。通常我們做短信或者郵件發(fā)送這些功能時(shí),會(huì)有一個(gè)隊(duì)列從數(shù)據(jù)庫(kù)或者緩存中讀取要發(fā)送的內(nèi)容進(jìn)行發(fā)送,如果成功了就不管了,如果失敗了會(huì)將短信的狀態(tài)改成失敗或者重發(fā)。在這里,我們直接將它改回到之前未發(fā)送的狀態(tài)然后等待下次發(fā)送的隊(duì)列再次執(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('手機(jī)號(hào)' . $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; }  // 模擬另一個(gè)線程查找發(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(); }

          說(shuō)明

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

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

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

          推薦學(xué)習(xí):《PHP視頻教程》

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