当前位置: 首页 > 财经 > 正文
Go设计模式--备忘录模式,带暂存的业务功能可以参考它来实现
来源:面包芯语    时间:2023-04-18 08:21:37

备忘录模式是一种行为型设计模式。这种模式允许我们保存对象在某些关键节点时的必要信息,以便于在适当的时候可以将之恢复到之前的状态。通常它可以用来帮助设计撤销/恢复操作。

备忘录模式的类结构

下面是备忘录模式的类图,

图片来自https://refactoringguru.cn/design-patterns/memento,我后面实现的时候不会完全按照这个结构去实现,这里先把结构里的各个角色给大家说清楚。


【资料图】

image.png

备忘录模式中主要有这三个角色的类

上面这个类图结构是实现备忘录模式的最简单方式,真实使用的时候,Caretaker,Originator、memento 这些角色可以继续抽象出对应的接口和实现。这里就不搞那么复杂了,要举的例子比较简单,这么一拆显得这个模式用起来特别费事儿。

其实其他设计模式也是一样,学习的时候大家知道了它的结构后,在实现应用的环节不必完完全全按照结构一板一眼地全部进行实现,有的应用场景并不复杂,能合并的角色可以按需进行合并。

应用举例

场景

某线上博客平台, 需为用户提供在线编辑文章功能,文章主要包括标题 - title 和内容 - content等信息。为最大程度防止异常情况导致编辑内容的丢失, 需要提供版本暂存和Undo, Redo功能。

"版本暂存"问题可以应用备忘录模式, 将编辑器的状态完整保存起来(主要就是编辑内容),Undo和Redo的本质, 是在历史版本中前后移动把当时保存的内容加载到文章对象上。

方案设计

这个例子里我们把原发器和管理人两个角色集中在Editor类型上一起实现,例子比较简单,就没有单独实现一个Article类型作为原发器角色,如果你想完全按照备忘录模式的结构实现,把Title、Content这写属性和Save方法抽离到单独的Article类型上,再让Editor嵌套组合Article即可。

下面我们根据UML类图实现一下这个带Undo、Redo功能的编辑器。

代码实现

首先在IEditor 接口里定义编辑器对象要实现的行为

//编辑器接口定义typeIEditorinterface{Title(titlestring)Content(contentstring)Save()Undo()errorRedo()errorShow()}

接下来定义编辑器的备忘录, 也就是编辑器的内部状态数据模型, 同时也对应一个历史版本。

"本文使用的完整可运行源码去公众号「网管叨bi叨」发送【设计模式】即可领取"typeMementostruct{titlestringcontentstringcreateTimeint64}funcnewMemento(titlestring,contentstring)*Memento{return&Memento{title,content,time.Now().Unix(),}}

然后是最复杂的Editor实现,它会实现上面IEditor接口中定义的所有行为,其中的Undo、Redo方法即回退、前进方法在实现的时候就是依赖的它内部记录的一组Memento对象,通过指向不同的Memento对象来实现回退和前进功能。

"本文使用的完整可运行源码去公众号「网管叨bi叨」发送【设计模式】即可领取"//编辑器类,实现IEditor接口typeEditorstruct{titlestringcontentstringversions[]*Mementoindexint}funcNewEditor()IEditor{return&Editor{"","",make([]*Memento,0),0,}}func(editor*Editor)Title(titlestring){editor.title=title}func(editor*Editor)Content(contentstring){editor.content=content}func(editor*Editor)Save(){it:=newMemento(editor.title,editor.content)editor.versions=append(editor.versions,it)editor.index=len(editor.versions)-1}func(editor*Editor)Undo()error{returneditor.load(editor.index-1)}func(editor*Editor)load(iint)error{size:=len(editor.versions)ifsize<=0{returnerrors.New("nohistoryversions")}ifi<0||i>=size{returnerrors.New("nomorehistoryversions")}it:=editor.versions[i]editor.title=it.titleeditor.content=it.contenteditor.index=ireturnnil}func(editor*Editor)Redo()error{returneditor.load(editor.index+1)}func(editor*Editor)Show(){fmt.Printf("MockEditor.Show,title=%s,content=%s\n",editor.title,editor.content)}

最后我们来测试一下Editor的版本记录功能

"本文使用的完整可运行源码去公众号「网管叨bi叨」发送【设计模式】即可领取"funcmain(){editor:=NewEditor()//testsave()editor.Title("唐诗")editor.Content("白日依山尽")editor.Save()editor.Title("唐诗登鹳雀楼")editor.Content("白日依山尽,黄河入海流.")editor.Save()editor.Title("唐诗登鹳雀楼王之涣")editor.Content("白日依山尽, 黄河入海流。欲穷千里目, 更上一层楼。")editor.Save()//testshow()fmt.Println("-------------Editor当前内容-----------")editor.Show()fmt.Println("-------------Editor回退内容-----------")for{e:=editor.Undo()ife!=nil{break}else{editor.Show()}}fmt.Println("-------------Editor前进内容-----------")for{e:=editor.Redo()ife!=nil{break}else{editor.Show()}}}

运行程序后会有类似下面的显示

image.png

本文的完整源码,已经同步收录到我整理的电子教程里啦,可向我的公众号「网管叨bi叨」发送关键字【设计模式】领取。

公众号「网管叨bi叨」发送关键字【设计模式】领取。

参考链接

扫码关注公众号「网管叨bi叨」

给网管个星标,第一时间吸我的知识

网管整理了一本《Go 开发参考书》收集了70多条开发实践。去公众号回复【gocookbook】领取!还有一本《k8s 入门实践》讲解了常用软件在K8s上的部署过程,公众号回复【k8s】即可领取!

觉得有用就点个在看

上一篇:

下一篇:

X 关闭

Copyright   2015-2022 欧洲周报网版权所有  备案号:沪ICP备2022005074号-23   联系邮箱: 58 55 97 3@qq.com