finish memento pattern

This commit is contained in:
Edward 2020-05-05 18:44:47 +08:00
parent c988ffc8ff
commit 2bd8e1560b
4 changed files with 100 additions and 39 deletions

View File

@ -26,9 +26,9 @@
+ [x] [模板方法模式(Template Method)](./behavior/05_template_method) + [x] [模板方法模式(Template Method)](./behavior/05_template_method)
+ [x] [策略模式(Strategy)](./behavior/12_strategy) + [x] [策略模式(Strategy)](./behavior/12_strategy)
+ [ ] [WIP][状态模式(State)](./behavior/behavior16_state) + [ ] [WIP][状态模式(State)](./behavior/behavior16_state)
+ [ ] [WIP][备忘录模式(Memento)](./behavior/09_memento) + [ ] [备忘录模式(Memento)](./behavior/09_memento)
+ [x] [访问者模式(Visitor)](./behavior/07_visitor) + [x] [访问者模式(Visitor)](./behavior/07_visitor)
+ [ ] [WIP][解释器模式(Interpreter)](./behavior/08_interpreter) + [x] [解释器模式(Interpreter)](./behavior/08_interpreter)
+ [x] [职责链模式(Chain of Responsibility)](./behavior/06_chain_of_responsibility) + [x] [职责链模式(Chain of Responsibility)](./behavior/06_chain_of_responsibility)

View File

@ -1,7 +1,16 @@
# 备忘录模式 # 备忘录模式
备忘录模式用于保存程序内部状态到外部,又不希望暴露内部状态的情形 备忘录模式,又叫快照模式,备份模式,用于在不暴露内部状态的情况下,保存程序内部状态到外部。
程序内部状态使用窄接口船体给外部进行存储,从而不暴露程序实现细节 主要保存的是数据(也就是状态),这些数据可以是静态数据,也可以是一个操作描述
备忘录模式同时可以离线保存内部状态,如保存到数据库,文件等。 在CQRS中的事件溯源模式(Event Sourcing)中,就是保存事件的操作(包含操作参数集)到持久化数据中,以达到事件回溯的目的.
现实生活中涉及备份和快照的例子就太多了,日常的打游戏存档,下次玩的时候,读取存档,读取进度,也是这个模式。
该模式中有三个关键角色:
1. 发起人角色 Originator 负责记录当前的内部状态,提供当前状态数据,并负责恢复备忘录数据。
2. 备忘录角色 Memento : 负责存放发起人对象某个时刻的内部状态,这就是要保存的数据结构类型。
3. 管理者角色 Caretaker: 负责保存备忘录对象。

View File

@ -1,35 +1,65 @@
package memento package memento
import "fmt" import (
"fmt"
"time"
)
type Memento interface{} ////////////////////////////////
//使用游戏玩家的角色存档和读取的例子
type Game struct { //GamePlayer 是一个Originator 提供当前的游戏状态
hp, mp int type GamePlayer struct {
hp, mp, role, level int //血量,魔法值,当前关卡
} }
type gameMemento struct { //RoleStatusMemento 一条备忘数据,存放瞬时状态的数据结构,一个数据结构
hp, mp int type RoleStatusMemento struct {
tag string //存档记录本身的名称,以便下次识别读取
hp, mp, level int //血量,魔法值,角色类型,当前关卡,
timeMark string //存档的可视化时间
} }
func (g *Game) Play(mpDelta, hpDelta int) { //RoleStatusCaretaker 负责保存角色当前的状态数据,提供存取能力
g.mp += mpDelta //RoleStatusCaretaker 也是占内存/存储的地方如果不停的读取IO压力会变大的很大
g.hp += hpDelta type RoleStatusCaretaker struct {
memens map[string]*RoleStatusMemento
} }
func (g *Game) Save() Memento { //SaveStatus 保存当前角色的游戏状态
return &gameMemento{ func (r *RoleStatusCaretaker) SaveStatus(item *RoleStatusMemento) {
r.memens[item.tag] = item
fmt.Printf("Game File %s Saved at %s\n", item.tag, item.timeMark)
}
//RetriveStatus 提供需要的状态
func (r *RoleStatusCaretaker) RetriveStatus(savedTag string) *RoleStatusMemento {
return r.memens[savedTag]
}
//Create 创建游戏的当前档案存档
func (g *GamePlayer) Create(tagName string) *RoleStatusMemento {
return &RoleStatusMemento{
tag: tagName,
hp: g.hp, hp: g.hp,
mp: g.mp, mp: g.mp,
level: g.level,
timeMark: time.Now().String(),
} }
} }
func (g *Game) Load(m Memento) { //Load 载入存档,恢复数据
gm := m.(*gameMemento) func (g *GamePlayer) Load(rm *RoleStatusMemento) {
g.mp = gm.mp g.mp = rm.mp
g.hp = gm.hp g.hp = rm.hp
g.level = rm.level
fmt.Printf("Game Profile had been restored to %s : %s\n", rm.tag, rm.timeMark)
} }
func (g *Game) Status() { //Status 玩家角色的当前状态
fmt.Printf("Current HP:%d, MP:%d\n", g.hp, g.mp) func (g *GamePlayer) Status() {
fmt.Printf("Current Level :%d HP:%d, MP:%d\n", g.level, g.hp, g.mp)
} }

View File

@ -1,22 +1,44 @@
package memento package memento
func ExampleGame() { import (
game := &Game{ "testing"
hp: 10, "time"
mp: 10, )
}
func TestGameArchive(t *testing.T) {
game.Status()
progress := game.Save() gamerole := GamePlayer{hp: 1000, mp: 232, level: 20}
game.Play(-2, -3) datakeeper := RoleStatusCaretaker{memens: make(map[string]*RoleStatusMemento)}
game.Status()
archive1 := gamerole.Create("第一次存档")
game.Load(progress)
game.Status() //交给管数据的人,存起来
datakeeper.SaveStatus(archive1)
// Output:
// Current HP:10, MP:10 //模拟,随机玩会儿游戏
// Current HP:7, MP:8 time.Sleep(time.Millisecond * 1132)
// Current HP:10, MP:10
//更新角色当前状态
gamerole = GamePlayer{hp: 500, mp: 10, level: 30}
//看一下状态
gamerole.Status()
archive2 := gamerole.Create("第二次存档")
//交给管数据的人,存起来
datakeeper.SaveStatus(archive2)
//准备恢复第一次的存档
//查找档案
restore1 := datakeeper.RetriveStatus("第一次存档")
//载入档案
gamerole.Load(restore1)
//看一下状态
gamerole.Status()
} }