go: Memento Pattern

项目结构:

image

 

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Memento Pattern备忘录模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/4/26 15:22
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : memento.go
*/
package entity

// Memento 备忘录顶层接口
// 企业级规范:面向接口编程,方便扩展不同类型备忘录
type Memento interface {
	GetID() string // 唯一标识
}

// ==============================================
// 以下为私有实现:外部包无法访问,保证封装性
// ==============================================

// bizMemento 业务备忘录(私有结构体,外部无法读写状态)
type bizMemento struct {
	id        string // 快照ID
	stateData []byte // 序列化后的原发器状态(二进制,绝对安全)
}

func (m *bizMemento) GetID() string {
	return m.id
}

// NewBizMemento 创建备忘录(仅内部包可调用)
func NewBizMemento(id string, state []byte) Memento {
	return &bizMemento{id: id, stateData: state}
}

// GetState 获取状态(仅内部包可调用)
func (m *bizMemento) GetState() []byte {
	return m.stateData
}


/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Memento Pattern备忘录模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/4/26 15:23
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : originator.go
*/
package entity

import "encoding/json"

// Originator 原发器接口
// 所有需要备份/回退的对象都必须实现该接口
type Originator interface {
	CreateMemento(id string) (Memento, error) // 创建快照
	RestoreFromMemento(m Memento) error       // 从快照恢复
}

// ==============================================
// 业务原发器示例:企业配置(可替换为订单/设备/商品)
// ==============================================

// EnterpriseConfig 企业配置(真实业务可替换为任意实体)
type EnterpriseConfig struct {
	CompanyID string  `json:"company_id"` // 企业ID
	Name      string  `json:"name"`       // 企业名称
	Version   int     `json:"version"`    // 配置版本
	Status    string  `json:"status"`     // 状态:enable/disable
	Balance   float64 `json:"balance"`    // 账户余额
}

// CreateMemento 创建备忘录:序列化状态为二进制(安全封装)
func (e *EnterpriseConfig) CreateMemento(id string) (Memento, error) {
	// 序列化为JSON二进制(可替换为Protobuf/gob)
	stateBytes, err := json.Marshal(e)
	if err != nil {
		return nil, err
	}
	return NewBizMemento(id, stateBytes), nil
}

// RestoreFromMemento 从备忘录恢复状态
func (e *EnterpriseConfig) RestoreFromMemento(m Memento) error {
	bizM := m.(*bizMemento)
	// 反序列化
	return json.Unmarshal(bizM.GetState(), e)
}

// 业务方法:修改状态
func (e *EnterpriseConfig) UpdateBalance(balance float64) {
	e.Balance = balance
	e.Version++
}

func (e *EnterpriseConfig) UpdateStatus(status string) {
	e.Status = status
	e.Version++
}

  

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Memento Pattern备忘录模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/4/26 15:23
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : memento_store.go
*/
package repository

import (
	"errors"
	"godesginpattern/memento/entity"
)

// MementoStore 备忘录存储接口
// 支持扩展:内存存储、Redis存储、MySQL存储
type MementoStore interface {
	Save(m entity.Memento) error           // 保存备忘录
	Get(id string) (entity.Memento, error) // 获取备忘录
	List() []entity.Memento                // 获取所有快照
}

// ==============================================
// 默认实现:内存存储(生产可替换)
// ==============================================

type memoryStore struct {
	mementos map[string]entity.Memento
}

func NewMemoryStore() MementoStore {
	return &memoryStore{
		mementos: make(map[string]entity.Memento),
	}
}

func (m *memoryStore) Save(me entity.Memento) error {
	m.mementos[me.GetID()] = me
	return nil
}

func (m *memoryStore) Get(id string) (entity.Memento, error) {
	me, ok := m.mementos[id]
	if !ok {
		return nil, errors.New("备忘录不存在")
	}
	return me, nil
}

func (m *memoryStore) List() []entity.Memento {
	list := make([]entity.Memento, 0, len(m.mementos))
	for _, v := range m.mementos {
		list = append(list, v)
	}
	return list
}

  

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Memento Pattern备忘录模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/4/26 15:23
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : memento_service'.go
*/
package service

import (
	"godesginpattern/memento/entity"
	"godesginpattern/memento/repository"
)

// MementoService 备忘录服务(Caretaker 负责人)
// 职责:只管理备忘录的保存、获取、回滚,不修改任何业务数据
type MementoService struct {
	store repository.MementoStore
}

func NewMementoService(store repository.MementoStore) *MementoService {
	return &MementoService{store: store}
}

// Backup 备份原发器状态
func (s *MementoService) Backup(originator entity.Originator, snapshotID string) error {
	m, err := originator.CreateMemento(snapshotID)
	if err != nil {
		return err
	}
	return s.store.Save(m)
}

// Rollback 回滚到指定快照
func (s *MementoService) Rollback(originator entity.Originator, snapshotID string) error {
	m, err := s.store.Get(snapshotID)
	if err != nil {
		return err
	}
	return originator.RestoreFromMemento(m)
}

// ListSnapshots 获取所有备份列表
func (s *MementoService) ListSnapshots() []entity.Memento {
	return s.store.List()
}

  

调用:

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Memento Pattern备忘录模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/4/26 18:54
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : mementobll.go
memento/
├── go.mod                  # 项目模块
├── internal/               # 内部包(外部不可访问)
│   ├── entity/             # 实体层:原发器、备忘录(核心数据)
│   │   ├── memento.go      # 备忘录接口 + 实现
│   │   └── originator.go   # 原发器接口 + 业务实体
│   ├── repository/         # 存储层:备忘录持久化/存储
│   │   └── memento_store.go
│   └── service/            # 服务层:负责人(Caretaker)核心逻辑
│       └── memento_service.go
└── cmd/                    # 应用层:入口、测试用例

	└── main.go
*/
package bll

import (
	"fmt"
	"godesginpattern/memento/entity"
	"godesginpattern/memento/repository"
	"godesginpattern/memento/service"
)

func MementoMain() {
	// ===================== 1. 初始化依赖(DI依赖注入) =====================
	store := repository.NewMemoryStore()        // 存储层
	memoSvc := service.NewMementoService(store) // 服务层

	// ===================== 2. 创建原发器(企业配置) =====================
	config := &entity.EnterpriseConfig{
		CompanyID: "COMPANY_001",
		Name:      "科技有限公司",
		Version:   1,
		Status:    "enable",
		Balance:   100000.00,
	}

	fmt.Println("===== 初始状态 =====")
	printConfig(config)

	// ===================== 3. 备份 V1 版本 =====================
	_ = memoSvc.Backup(config, "SNAPSHOT_V1")
	fmt.Println("\n✅ 已备份 SNAPSHOT_V1")

	// ===================== 4. 修改状态 =====================
	config.UpdateBalance(80000.00)
	config.UpdateStatus("disable")

	fmt.Println("\n===== 修改后状态 V2 =====")
	printConfig(config)

	// ===================== 5. 备份 V2 版本 =====================
	_ = memoSvc.Backup(config, "SNAPSHOT_V2")
	fmt.Println("\n✅ 已备份 SNAPSHOT_V2")

	// ===================== 6. 再次修改 =====================
	config.UpdateBalance(50000.00)
	fmt.Println("\n===== 二次修改状态 =====")
	printConfig(config)

	// ===================== 7. 回滚到 V1 =====================
	fmt.Println("\n🔄 回滚到 SNAPSHOT_V1")
	_ = memoSvc.Rollback(config, "SNAPSHOT_V1")
	printConfig(config)

	// ===================== 8. 回滚到 V2 =====================
	fmt.Println("\n🔄 回滚到 SNAPSHOT_V2")
	_ = memoSvc.Rollback(config, "SNAPSHOT_V2")
	printConfig(config)
}

// printConfig 打印配置状态
func printConfig(c *entity.EnterpriseConfig) {
	fmt.Printf("企业ID:%s\n名称:%s\n版本:%d\n状态:%s\n余额:%.2f\n",
		c.CompanyID, c.Name, c.Version, c.Status, c.Balance)
}

 

输出:

image

 

posted @ 2026-04-26 19:00  ®Geovin Du Dream Park™  阅读(16)  评论(0)    收藏  举报