7

手撸golang 行为型设计模式 备忘录模式

 3 years ago
source link: https://studygolang.com/articles/33275
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

手撸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)

有疑问加站长微信联系(非本文作者)

eUjI7rn.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK