动态

详情 返回 返回

[設計模式]行為型-備忘錄模式 - 动态 详情

簡介

備忘錄模式(Memento Pattern)是一種行為型設計模式,它允許生成對象狀態的快照並在以後將其還原。備忘錄模式不會影響它所處理對象的內部結構,也不會影響快照中存儲的數據。簡單來説,它就像遊戲中的“保存”和“加載”功能。

組成角色:

  • Originator(發起人): 主要用於生成自身狀態的快照,在需要時可以通過快照恢復自身狀態。
  • Memento(備忘錄): 一個對象,用於存儲Originator在某個特定時間點的內部狀態。備忘錄對Originator之外的對象是不可見的,這樣可以保護Originator的狀態不被外部修改。通常將備忘錄類設置為不可變的類,並且通過構造函數一次性傳遞數據。
  • Caretaker(管理者): 負責保存和管理備忘錄對象,但不檢查備忘錄的內容,只知道何時和為何捕捉Originator的狀態,以及何時恢復Originator的狀態。

常見使用場景

  • 撤銷/重做功能: 許多應用程序(如文本編輯器、圖形編輯器)都提供了撤銷和重做操作。備忘錄模式可以用來保存每次操作之前的狀態,以便進行撤銷。
  • 事務管理: 在某些事務處理系統中,可能需要在事務失敗時回滾到之前的狀態。備忘錄模式可以用來保存事務開始前的狀態。
  • 程序狀態的快照和恢復: 有時需要定期保存程序的狀態,以便在出現問題時能夠恢復到最近的穩定狀態。
  • 遊戲中的保存和加載: 遊戲通常需要保存玩家的進度,並在需要時加載。備忘錄模式非常適合這種場景。

優點

  • 封裝性好: Originator的狀態被封裝在Memento中,對外部不可見,保證了狀態的安全性。
  • 簡化了Originator: Originator只需要負責創建和恢復備忘錄,而不需要關心備忘錄的管理。備忘錄的管理交由Caretaker負責。
  • 支持歷史版本: 可以保存Originator的多個歷史狀態,方便進行多次撤銷或恢復。

缺點

  • 內存消耗: 如果需要保存的狀態很多或者狀態很大,可能會消耗大量的內存。
  • 管理複雜性: Caretaker需要管理多個備忘錄對象,可能會增加管理的複雜性。
  • 狀態恢復的性能開銷: 恢復狀態可能涉及到複雜的數據複製操作,可能會有一定的性能開銷。

示例代碼

Simple

Go

package memento

type Memento struct {
	state int
}

func NewMemento(value int) *Memento {
	return &Memento{
		state: value,
	}
}

type Originator struct {
	value int
}

func NewOriginator(value int) *Originator {
	return &Originator{
		value: value,
	}
}

func (o *Originator) TenTimes() {
	o.value *= 10
}

func (o *Originator) HalfTimes() {
	o.value /= 2
}

func (o *Originator) Value() int {
	return o.value
}

func (o *Originator) CreateMemento() *Memento {
	return NewMemento(o.value)
}

func (o *Originator) RestoreMemento(m *Memento) {
	o.value = m.state
}

type Caretaker struct {
	Mementos []*Memento
}

func (c *Caretaker) AddMemento(m *Memento) {
	c.Mementos = append(c.Mementos, m)
}

func (c *Caretaker) GetMemento(index int) *Memento {
	return c.Mementos[index]
}

客户端

package memento

import (
	"fmt"
	"testing"
)

func TestSimple(t *testing.T) {
	caretaker := &Caretaker{
		Mementos: make([]*Memento, 0),
	}

	n := NewOriginator(10)

	caretaker.AddMemento(n.CreateMemento())
	n.TenTimes()
	fmt.Printf("Current value: %d\n", n.Value())

	caretaker.AddMemento(n.CreateMemento())
	n.TenTimes()
	fmt.Printf("Current value: %d\n", n.Value())

	n.RestoreMemento(caretaker.GetMemento(0))
	fmt.Printf("Current value after restore: %d\n", n.Value())
}

執行輸出

Current value: 100
Current value: 1000
Current value after restore: 10

Python

from typing import List


class Memento:
    """
    備忘錄類
    """

    def __init__(self, value: int):
        self._value = value

    @property
    def value(self) -> int:
        """用 property 實現屬性只讀"""
        return self._value


class Originator:
    """
    發起人類
    """

    def __init__(self, value: int):
        self._value = value

    def ten_times(self):
        self._value *= 10

    def half_times(self):
        self._value /= 2

    def get_value(self) -> int:
        return self._value

    def create_memento(self) -> Memento:
        return Memento(self._value)

    def restore_memento(self, memento: Memento):
        self._value = memento.value


class Caretaker:
    """負責人類"""

    def __init__(self):
        self._mems: List[Memento] = []

    def add_memento(self, memento: Memento):
        self._mems.append(memento)

    def get_memento(self, index: int) -> Memento:
        return self._mems[index]


if __name__ == "__main__":
    caretaker = Caretaker()

    n = Originator(10)
    caretaker.add_memento(n.create_memento())
    n.ten_times()
    print(f"current value: {n.get_value()}")

    caretaker.add_memento(n.create_memento())
    n.ten_times()
    print(f"current value: {n.get_value()}")

    n.restore_memento(caretaker.get_memento(0))
    print(f"current value after restore: {n.get_value()}")

執行輸出

current value: 100
current value: 1000
current value after restore: 10
user avatar ai-hpc-trivia 头像 u_16018702 头像 lying7 头像 kuailedehuanggua 头像 hedzr 头像 shimiandehoutao 头像 seven97_top 头像
点赞 7 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.