当前位置: 首页 > 后端技术 > PHP

PHP设计模式的备忘录模式

时间:2023-03-30 02:39:39 PHP

备忘录,这个名字其实很形象的说明了它的作用。一个典型的例子就是我们原来玩硬盘游戏时的存档功能。当你对即将面对的大boss有所顾虑时,一般都会先保存一个进度档。如果挑战失败,可以直接读取存档恢复挑战BOSS前的状态,然后就可以愉快的去修炼一会回来解决这个大BOSS了。不过为了以防万一,挑战BOSS前还是先存个档为好。再比如我们码农日常使用的代码管理工具Git或者Svn。每次提交都像是存档备份。当新代码出现问题时,回滚恢复即可。以上就是备忘录模式的典型应用,下面我们一起来看看这个模式吧。GoF类图及解释GoF定义:在不破坏封装的前提下,捕获一个对象的内部状态,并将这个状态保存在对象外部。这样在以后的GoF类图代码实现类Originator{private$state;中就可以将对象恢复到原来保存的状态。公共函数SetMeneto(Memento$m){$this->state=$m->GetState();}publicfunctionCreateMemento(){$m=newMemento();$m->SetState($this->state);返回$m;}publicfunctionSetState($state){$this->state=$state;}publicfunctionShowState(){echo$this->state,PHP_EOL;}}发起者也可以称为发起者。它有一个内部状态(state),可以在不同的情况下改变。当事件发生时,状态需要恢复到原来的状态。在这里,我们有一个CreateMemento()来创建备忘录(存档),还有一个SetMeneto()来恢复状态(阅读)。类纪念品{private$state;公共函数SetState($state){$this->state=$state;}publicfunctionGetState(){return$this->state;}}Memento,很简单,就是用来记录状态的。以对象的形式保存这种状态,可以让发起者很容易地创建很多档案来记录各种状态。类看门人{private$memento;公共功能SetMemento($memento){$this->memento=$memento;}publicfunctionGetMemento(){return$this->memento;}}负责人,也叫经理类,保存Memo,需要的时候从这里取memo。只负责保存,不能修改备忘录。在复杂的应用中,可以把这个做成一个列表,就像在游戏中一样,可以有选择地展示多个存档记录,供玩家选择。$o=newOriginator();$o->SetState('State1');$o->ShowState();//保存状态$c=newCaretaker();$c->SetMemento($o->CreateMemento());$o->SetState('State2');$o->ShowState();//恢复状态$o->SetMeneto($c->GetMemento());$o->ShowState();在客户端调用中,我们的发起者初始化状态并保存,然后人为改变状态。这时候你只需要通过负责人来恢复状态即可。memo模式说白了就是让一个外部类B保存A的内部状态,然后在合适的时候方便的恢复这个状态。备忘录模式的应用场景其实有很多,比如浏览器回滚、数据库备份还原、操作系统备份还原、文档撤销重做、棋局遗憾等。这种模式可以保持原生成器的包装,并且也正是这些状态需要对外部对象隐藏,所以只能交给一个memo对象来记录状态。原创者和备忘录之间的复制可能会导致性能问题,尤其是大对象复杂和众多的内部状态,也会带来一些编码漏洞,比如Mac的时间机器功能在某些状态下是缺失的。你听说过吗,可以将电脑恢复到某个时间点的状态。其实windows的ghost也有类似的功能。我们也决定在我们的手机操作系统上开发这样的功能。当我们点击TimeMachineBackup时,手机上的所有信息、数据和状态信息都会被压缩保存。如果用户允许,我们会将这个压缩包上传到我们的云服务器,避免占用用户的手机内存,否则就只能保存在用户的手机内存中。当用户的手机需要恢复到某个时间点时,我们列出所有的时光机备份,用户只需要轻轻一按手指,就可以将手机系统状态恢复到当时的状态。是不是很方便!!完整代码: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.phpto=$to;$this->content=$content;$this->state='未发送';$this->time=time();}publicfunctionShow(){echo$this->to,'---',$this->content,'---',$this->time,'---',$this->state,PHP_EOL;}publicfunctionCreateSaveSate(){$ss=newSaveState();$ss->SetState($this->state);返回$ss;}publicfunctionSetSaveState($ss){if($this->state!=$ss->GetState()){$this->time=time();}$this->state=$ss->GetState();}publicfunctionSetState($state){$this->state=$state;}公共功能GetState(){返回$this->state;}}classSaveState{private$state;公共函数SetState($state){$this->state=$state;}publicfunctionGetState(){return$this->state;}}classStateContainer{private$ss;公共函数SetSaveState($ss){$this->ss=$ss;}publicfunctionGetSaveState(){return$this->ss;}}//模拟短信发送$mList=[];$scList=[];for($i=0;$i<10;$i++){$m=newMessage('手机号码'.$i,'内容'.$i);echo'初始状态:';$m->显示();//保存初始信息$sc=newStateContainer();$sc->SetSaveState($m->CreateSaveSate());$scList[]=$sc;//模拟短信发送,2发送成功,3发送失败$pushState=mt_rand(2,3);$m->SetState($pushState==2?'发送成功':'发送失败');echo'发布后状态:';$m->显示();$mList[]=$m;}//模拟另一个线程找到发送失败的并恢复到未发送状态sleep(2);foreach($mListas$k=>$m){if($m->GetState()=='发送失败'){//如果发送失败,恢复状态$m->SetSaveState($scList[$k]->GetSaveState());}echo'查询发布失败后的状态:';$m->Show();}说明短信类作为我们的原始发送者,在发送前保存当前发送状态,随机模拟短信发送。只有两种状态,发送成功或者失败,把原来发送者的状态改成成功或者失败,模拟另一个线程或者脚本检查短信的发送状态,如果发现失败就改回未发送地位。这里我们只保存发送状态字段,不保存其他发送者的内部属性。在真实场景中,我们应该对重试次数进行限制。当超过此数量时,状态将变为发送完全失败,并且不再重试。接下来要看的就是备忘录模式,也就是我们平时日常使用的模式,叫备忘录,倒不如说后悔模式更贴切。人生没有后悔药,但可以在程序的世界里找到。还是那句话,养成备份重要文件、数据、代码的好习惯,灵活使用Git(不仅仅是存储代码,比如这篇系统文章)。下次我们要遇到的桥接模式并不陌生,虚拟机上的网络配置都有桥接模式,那么这个东西是干什么用的呢?且听下一章。各媒体平台均可搜索【硬核项目经理】