《golang设计模式》第三部分·行为型模式-06-备忘录模式(Memento)

文章目录

  • [1. 概述](#1. 概述)
    • [1.1 角色](#1.1 角色)
    • [1.2 类图](#1.2 类图)
  • [2. 代码示例](#2. 代码示例)
    • [2.1 设计](#2.1 设计)
    • [2.2 代码](#2.2 代码)
    • [2.3 类图](#2.3 类图)

1. 概述

备忘录(Memento)用于在不破坏目标对象封装特性的基础上,将目标对象内部的状态存储到外部对象中,以备之后恢复状态时使用。

1.1 角色

  • Originator(发起者):当前的基础对象,它会将自己的状态保存进备忘录。
    • savememento()方法:Originator通过该方法将它自己状态保存进一个备忘录对象。
    • restorememento()方法:Originator通过该方法将它自己状态回滚至指定备忘录。
  • Memento(备忘录) : 存储Originator状态的对象
  • Caretaker(管理者):保存多条备忘录的对象,并维护着备忘录的索引,在需要的时候会返回相应的备忘录。

1.2 类图

Originator -state:State +RestoreState(m:Memento) +CreateMemento() Memento -state:State +GetState() Caretaker +StoreMemento(m:Memento) +GetMemento(c:Condition)

2. 代码示例

2.1 设计

  • 定义备忘录memento来记录发起者状态
  • 它的Get()方法获取它的状态
  • 定义发起者Originator
    • 它的方法 CreateMemento() 用它自己创建一条备忘录
    • 它的方法 RollBack() 将它自己回滚至指定备忘录的状态
    • 它的Set()方法可以设置它的状态
    • 它的Get()方法可以获取它的状态
  • 创建一个管理者Caretaker,它是备忘录Memento的聚合
    • 它的AddMemento方法,向它自身加入一条备忘录
    • 它的GetMemento()方法,查询一条它管理的指定备忘录
  • 调用
    • 初始化
      • 实例化一个管理者caretaker
      • 实例化一个发起者originator
    • 创建备忘录测试
      • 第一次
        • 用发起者创建一条备忘录
        • 管理者收录该备忘录
      • 第二次
        • 改变发起者状态
        • 用发起者创建一条新备忘录
        • 管理者收录该备忘录
      • 第三次
        • 改变发起者状态
        • 用发起者创建一条新备忘录
        • 管理者收录该备忘录
      • 查看管理者信息,应该有三条备忘录
    • 回滚测试
      • 从管理者获取指定索引的备忘录
      • 将发起者回滚至该备忘录状态

2.2 代码

  • 代码
go 复制代码
package main

import "fmt"

// 定义备忘录
type Memento struct {
	state string
}

// 查备忘录状态
func (m *Memento) Get() string {
	return m.state
}

// 定义发起者
type Originator struct {
	state string
}

// 根据发起者状态创建一条备忘录
func (e *Originator) CreateMemento() (memento *Memento) {
	memento = &Memento{state: e.state}
	fmt.Printf("创建一条备忘录:%+v\n", memento)
	return memento
}

// 将发起者状态回滚至指定备忘录状态
func (e *Originator) RollBack(m *Memento) {
	e.state = m.Get()
	fmt.Printf("发起者状态回滚至:%v\n", e)
}

// 设置发起者状态
func (e *Originator) Set(state string) {
	e.state = state
	fmt.Println("发起者状态更改为:", e.state)
}

// 获取发起者状态
func (e *Originator) Get() string {
	fmt.Println("获取发起者状态为:", e.state)
	return e.state
}

// 定义管理者,管理者是备忘录的聚合
type Caretaker struct {
	mementoArray []*Memento
}

// 向管理者中添加一条备忘录
func (c *Caretaker) AddMemento(m *Memento) {
	fmt.Printf("向管理者中添加一条备忘录:%+v\n", m)
	c.mementoArray = append(c.mementoArray, m)
}

// 获取指定备忘录信息
func (c *Caretaker) GetMemento(index int) *Memento {
	fmt.Printf("获取到第 %d 条备忘录信息为:%+v\n", index, c.mementoArray[index])
	return c.mementoArray[index]
}

func main() {
	//实例化一个管理者
	caretaker := &Caretaker{
		mementoArray: make([]*Memento, 0),
	}
	//实例化一个发起者
	originator := &Originator{
		state: "A",
	}

	//为发起者创建一条备忘录
	memento0 := originator.CreateMemento()
	//在管理者中加入该备忘录
	caretaker.AddMemento(memento0)

	//改变发起者状态
	originator.Set("B")
	//为发起者创建第二条备忘录
	memento1 := originator.CreateMemento()
	//在管理者中加入该备忘录
	caretaker.AddMemento(memento1)

	//再次改变发起者状态
	originator.Set("C")
	//为发起者创建第三条备忘录
	memento2 := originator.CreateMemento()
	//在管理者中加入该备忘录
	caretaker.AddMemento(memento2)
	fmt.Println("此时管理者应该有三条备忘录:")
	for _, memento := range caretaker.mementoArray {
		fmt.Printf("%+v\n", memento)
	}
	
	fmt.Println("=========回滚测试===========")
	originator.RollBack(caretaker.GetMemento(1))
	fmt.Println("=========回滚测试===========")
	originator.RollBack(caretaker.GetMemento(0))
}
  • 输出
shell 复制代码
创建一条备忘录:&{state:A}
向管理者中添加一条备忘录:&{state:A} 
发起者状态更改为: B
创建一条备忘录:&{state:B}
向管理者中添加一条备忘录:&{state:B} 
发起者状态更改为: C
创建一条备忘录:&{state:C}
向管理者中添加一条备忘录:&{state:C} 
此时管理者应该有三条备忘录
&{state:A}
&{state:B}
&{state:C}
=========回滚测试===========
获取到第 1 条备忘录信息为:&{state:B}
发起者状态回滚至:&{B}
=========回滚测试===========
获取到第 0 条备忘录信息为:&{state:A}
发起者状态回滚至:&{A}

2.3 类图

Originator -string:State +CreateMemento() +RollBack(m *Memento) +Set(state string) +Get() Memento -String:State +Get() Caretaker +[]*Memento:mementoArray +AddMemento(m *Memento) +GetMemento(index int) : Memento


相关推荐
nbsaas-boot1 小时前
slice / map 在 Go GC 与内存碎片上的真实成本
开发语言·后端·golang
源代码•宸2 小时前
Leetcode—1266. 访问所有点的最小时间【简单】
开发语言·后端·算法·leetcode·职场和发展·golang
Tiny_React3 小时前
Claude Code Skills 自优化架构设计
人工智能·设计模式
源代码•宸4 小时前
Leetcode—85. 最大矩形【困难】
经验分享·算法·leetcode·职场和发展·golang·单调栈
精神小伙就是猛4 小时前
C# Task/ThreadPool async/await对比Golang GMP
开发语言·golang·c#
techdashen5 小时前
Go 1.18+ slice 扩容机制详解
开发语言·后端·golang
「、皓子~5 小时前
AI创作系列35 海狸IM桌面版:本地数据库的设计艺术
数据库·golang·毕业设计·开源软件·im·社交软件
DICOM医学影像6 小时前
4. go语言从零实现以太坊客户端 - 区块链转账
golang·区块链·以太坊·web3.0·geth
天天进步20156 小时前
KrillinAI 源码级深度拆解三:声音的克隆与新生——解析 KrillinAI 接入 GPT-SoVITS/CosyVoice 的配音逻辑
golang
UpgradeLink6 小时前
基于 Go 打造的升级链路管理平台:upgradelink 让设备升级更简单
开发语言·后端·golang