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] [策略模式(Strategy)](./behavior/12_strategy)
+ [ ] [WIP][状态模式(State)](./behavior/behavior16_state)
+ [ ] [WIP][备忘录模式(Memento)](./behavior/09_memento)
+ [ ] [备忘录模式(Memento)](./behavior/09_memento)
+ [x] [访问者模式(Visitor)](./behavior/07_visitor)
+ [ ] [WIP][解释器模式(Interpreter)](./behavior/08_interpreter)
+ [x] [解释器模式(Interpreter)](./behavior/08_interpreter)
+ [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
import "fmt"
import (
"fmt"
"time"
)
type Memento interface{}
////////////////////////////////
//使用游戏玩家的角色存档和读取的例子
type Game struct {
hp, mp int
//GamePlayer 是一个Originator 提供当前的游戏状态
type GamePlayer struct {
hp, mp, role, level int //血量,魔法值,当前关卡
}
type gameMemento struct {
hp, mp int
//RoleStatusMemento 一条备忘数据,存放瞬时状态的数据结构,一个数据结构
type RoleStatusMemento struct {
tag string //存档记录本身的名称,以便下次识别读取
hp, mp, level int //血量,魔法值,角色类型,当前关卡,
timeMark string //存档的可视化时间
}
func (g *Game) Play(mpDelta, hpDelta int) {
g.mp += mpDelta
g.hp += hpDelta
//RoleStatusCaretaker 负责保存角色当前的状态数据,提供存取能力
//RoleStatusCaretaker 也是占内存/存储的地方如果不停的读取IO压力会变大的很大
type RoleStatusCaretaker struct {
memens map[string]*RoleStatusMemento
}
func (g *Game) Save() Memento {
return &gameMemento{
//SaveStatus 保存当前角色的游戏状态
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,
mp: g.mp,
level: g.level,
timeMark: time.Now().String(),
}
}
func (g *Game) Load(m Memento) {
gm := m.(*gameMemento)
g.mp = gm.mp
g.hp = gm.hp
//Load 载入存档,恢复数据
func (g *GamePlayer) Load(rm *RoleStatusMemento) {
g.mp = rm.mp
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() {
fmt.Printf("Current HP:%d, MP:%d\n", g.hp, g.mp)
//Status 玩家角色的当前状态
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
func ExampleGame() {
game := &Game{
hp: 10,
mp: 10,
}
game.Status()
progress := game.Save()
game.Play(-2, -3)
game.Status()
game.Load(progress)
game.Status()
// Output:
// Current HP:10, MP:10
// Current HP:7, MP:8
// Current HP:10, MP:10
import (
"testing"
"time"
)
func TestGameArchive(t *testing.T) {
gamerole := GamePlayer{hp: 1000, mp: 232, level: 20}
datakeeper := RoleStatusCaretaker{memens: make(map[string]*RoleStatusMemento)}
archive1 := gamerole.Create("第一次存档")
//交给管数据的人,存起来
datakeeper.SaveStatus(archive1)
//模拟,随机玩会儿游戏
time.Sleep(time.Millisecond * 1132)
//更新角色当前状态
gamerole = GamePlayer{hp: 500, mp: 10, level: 30}
//看一下状态
gamerole.Status()
archive2 := gamerole.Create("第二次存档")
//交给管数据的人,存起来
datakeeper.SaveStatus(archive2)
//准备恢复第一次的存档
//查找档案
restore1 := datakeeper.RetriveStatus("第一次存档")
//载入档案
gamerole.Load(restore1)
//看一下状态
gamerole.Status()
}