手撸 golang 行为型设计模式 备忘录模式
缘起
最近温习设计模式
拜读谭勇德的 << 设计模式就该这样学 >>
本系列笔记拟采纳 golang 练习之
备忘录模式
备忘录模式(Memento Pattern)又叫作快照模式(Snapshot Pattern),
或令牌模式(Token Pattern),指在不毁坏封装的前提下,捕捉一个对象的外部状态,并在对象之外保留这个状态。这样当前就可将该对象复原到原先保留的状态,属于行为型设计模式。备忘录模式次要实用于以下利用场景。(1)须要保留历史快照的场景。(2)心愿在对象之外保留状态,且除了本人,其余类对象无法访问状态保留的具体内容。(摘自 谭勇德 << 设计模式就该这样学 >>)
场景
- 某线上博客平台, 需为用户提供在线编辑文章性能
- 文章次要包含题目 – title 和内容 – content 等信息
- 为最大水平避免异常情况导致编辑内容的失落, 须要提供版本暂存和 Undo, Redo 性能
- “ 版本暂存 ” 问题能够利用 备忘录模式, 将编辑器的状态残缺保留(次要就是编辑内容)
- Undo 和 Redo 的实质, 是在历史版本中前后挪动
设计
- IEditor: 定义编辑器接口
- tEditorMemento: 定义编辑器的备忘录, 也就是编辑器的外部状态数据模型, 同时也对应一个历史版本
- tMockEditor: 虚构的编辑器类, 实现 IEditor 接口
单元测试
memento_pattern_test.go
package behavioral_patterns
import (
"learning/gooop/behavioral_patterns/memento"
"testing"
)
func Test_MementoPattern(t *testing.T) {editor := memento.NewMockEditor()
// test save()
editor.Title("唐诗")
editor.Content("白日依山尽")
editor.Save()
editor.Title("唐诗 登鹳雀楼")
editor.Content("白日依山尽, 黄河入海流.")
editor.Save()
editor.Title("唐诗 登鹳雀楼 王之涣")
editor.Content("白日依山尽, 黄河入海流。欲穷千里目, 更上一层楼。")
editor.Save()
// test show()
editor.Show()
// test undo()
for {e := editor.Undo()
if e != nil {break} else {editor.Show()
}
}
// test redo()
for {e := editor.Redo()
if e != nil {break} else {editor.Show()
}
}
}
测试输入
$ go test -v memento_pattern_test.go
=== RUN Test_MementoPattern
tMockEditor.Show, title= 唐诗 登鹳雀楼 王之涣, content= 白日依山尽, 黄河入海流。欲穷千里目, 更上一层楼。tMockEditor.Show, title= 唐诗 登鹳雀楼, content= 白日依山尽, 黄河入海流.
tMockEditor.Show, title= 唐诗, content= 白日依山尽
tMockEditor.Show, title= 唐诗 登鹳雀楼, content= 白日依山尽, 黄河入海流.
tMockEditor.Show, title= 唐诗 登鹳雀楼 王之涣, content= 白日依山尽, 黄河入海流。欲穷千里目, 更上一层楼。--- PASS: Test_MementoPattern (0.00s)
PASS
ok command-line-arguments 0.002s
IEditor.go
定义编辑器接口
package memento
type IEditor interface {Title(title string)
Content(content string)
Save()
Undo() error
Redo() error
Show()}
tEditorMemento.go
定义编辑器的备忘录, 也就是编辑器的外部状态数据模型, 同时也对应一个历史版本
package memento
import "time"
type tEditorMemento struct {
title string
content string
createTime int64
}
func newEditorMememto(title string, content string) *tEditorMemento {
return &tEditorMemento{title, content, time.Now().Unix(),}
}
tMockEditor.go
虚构的编辑器类, 实现 IEditor 接口
package memento
import (
"errors"
"fmt"
)
type tMockEditor struct {
title string
content string
versions []*tEditorMemento
index int
}
func NewMockEditor() IEditor {
return &tMockEditor{"","", make([]*tEditorMemento, 0), 0,
}
}
func (me *tMockEditor) Title(title string) {me.title = title}
func (me *tMockEditor) Content(content string) {me.content = content}
func (me *tMockEditor) Save() {it := newEditorMememto(me.title, me.content)
me.versions = append(me.versions, it)
me.index = len(me.versions) - 1
}
func (me *tMockEditor) Undo() error {return me.load(me.index - 1)
}
func (me *tMockEditor) load(i int) error {size := len(me.versions)
if size <= 0 {return errors.New("no history versions")
}
if i < 0 || i >= size {return errors.New("no more history versions")
}
it := me.versions[i]
me.title = it.title
me.content = it.content
me.index = i
return nil
}
func (me *tMockEditor) Redo() error {return me.load(me.index + 1)
}
func (me *tMockEditor) Show() {fmt.Printf("tMockEditor.Show, title=%s, content=%s\n", me.title, me.content)
}
备忘录模式小结
备忘录模式的长处(1)简化发起人实体类(Originator)的职责,隔离状态存储与获取,实现了信息的封装,客户端毋庸关怀状态的保留细节。(2)提供状态回滚性能。备忘录模式的毛病
备忘录模式的毛病次要是耗费资源。如果须要保留的状态过多,则每一次保留都会耗费很多内存。(摘自 谭勇德 << 设计模式就该这样学 >>)
(end)