备忘录模式是一种行为型设计模式。这种模式允许我们保存对象在某些关键节点时的必要信息,以便于在适当的时候可以将之恢复到之前的状态。通常它可以用来帮助设计撤销/恢复操作。
备忘录模式的类结构
下面是备忘录模式的类图,
图片来自https://refactoringguru.cn/design-patterns/memento,我后面实现的时候不会完全按照这个结构去实现,这里先把结构里的各个角色给大家说清楚。
【资料图】
备忘录模式中主要有这三个角色的类
上面这个类图结构是实现备忘录模式的最简单方式,真实使用的时候,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()}}}运行程序后会有类似下面的显示
本文的完整源码,已经同步收录到我整理的电子教程里啦,可向我的公众号「网管叨bi叨」发送关键字【设计模式】领取。
参考链接
扫码关注公众号「网管叨bi叨」
给网管个星标,第一时间吸我的知识
网管整理了一本《Go 开发参考书》收集了70多条开发实践。去公众号回复【gocookbook】领取!还有一本《k8s 入门实践》讲解了常用软件在K8s上的部署过程,公众号回复【k8s】即可领取!
觉得有用就点个在看
X 关闭
-
Go设计模式--备忘录模式,带暂存的业务功能可以参考它来实现
大家好,这里是每周都在陪你一起进步的网管~!今天继续学习设计模式—备忘录模式备忘录模式(MementoPatte
-
武穴市气象台解除大风蓝色预警【IV级/一般】-世界新消息
据国家突发事件预警信息发布网:武穴市气象台04月18日02时18分解除04月14日07时13分发布的大风蓝色预警信号。
-
科技与医药赛道火热 基金投顾争相布局 世界观速讯
4月以来,华安基金、交银施罗德基金、富国基金、华夏基金、银华基金等多家基金公司调整了投顾组合的持仓策
-
凉面条的做法_凉面条
1、凉面、丝瓜、油、盐、花生仁、麻椒油、香油、香莱末、味精、老干妈辣椒酱、生抽酱油。2、最先将鲜面条煮
-
枣阳市气象台发布雷电黄色预警【III级/较重】
据国家突发事件预警信息发布网:枣阳市气象台2023年04月17日20时20分发布雷电黄色预警信号:预计未来6小时
-
小米5s Plus双镜头手机 远传资费独家上市
5 7吋大萤幕的双镜头手机小米5sPlus继11 10在小米站开卖之后,明日(11 15)起在全台远传电信门
