手撸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_patternsimport (    "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_MementoPatterntMockEditor.Show, title=唐诗 登鹳雀楼 王之涣, content=白日依山尽, 黄河入海流。欲穷千里目, 更上一层楼。tMockEditor.Show, title=唐诗 登鹳雀楼, content=白日依山尽, 黄河入海流. tMockEditor.Show, title=唐诗, content=白日依山尽tMockEditor.Show, title=唐诗 登鹳雀楼, content=白日依山尽, 黄河入海流. tMockEditor.Show, title=唐诗 登鹳雀楼 王之涣, content=白日依山尽, 黄河入海流。欲穷千里目, 更上一层楼。--- PASS: Test_MementoPattern (0.00s)PASSok      command-line-arguments  0.002s

IEditor.go

定义编辑器接口

package mementotype IEditor interface {    Title(title string)    Content(content string)    Save()    Undo() error    Redo() error    Show()}

tEditorMemento.go

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

package mementoimport "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 mementoimport (    "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)