怎樣用Golang實現備忘錄模式 實現對象狀態保存與恢復

備忘錄模式用于保存并恢復對象狀態,其核心在于定義備忘錄結構、實現發起人和管理者。1. 定義備忘錄結構體memento,保存關鍵狀態字段content;2. 創建發起人texteditor,實現save()生成快照和restore()恢復狀態;3. 使用管理者caretaker管理多個快照,通過add()添加、undo()撤銷、redo()重做、current()獲取當前快照;4. 實際使用時通過組合上述結構實現內容編輯與狀態切換;5. 建議關注深拷貝、內存限制、序列化及并發性能等問題。

怎樣用Golang實現備忘錄模式 實現對象狀態保存與恢復

備忘錄模式的核心是保存對象的某個狀態,以便后續可以恢復。在go語言中,雖然沒有類的概念,但通過結構體和接口,我們完全可以實現類似的功能。

怎樣用Golang實現備忘錄模式 實現對象狀態保存與恢復

這篇文章講的是:如何用golang實現備忘錄模式,讓一個對象的狀態可以被保存并恢復。

怎樣用Golang實現備忘錄模式 實現對象狀態保存與恢復


定義備忘錄結構

要保存對象狀態,首先得有一個“備忘錄”結構體,用來存儲你想保留的數據。這個結構體應該盡可能輕量,只包含需要保存的狀態字段。

立即學習go語言免費學習筆記(深入)”;

比如,假設你有一個文本編輯器結構體 TextEditor,你想保存它的內容:

怎樣用Golang實現備忘錄模式 實現對象狀態保存與恢復

type Memento struct {     content string }

這個結構體就是你的“快照”,它記錄了某一時刻的內容。不需要暴露給外部修改,所以字段可以小寫開頭(非導出),這樣封裝性更好。


創建發起人(Originator)

發起人是那個擁有狀態、能創建備忘錄、也能從備忘錄恢復狀態的對象。在Go中,你可以用結構體加方法的方式來實現。

繼續上面的例子:

type TextEditor struct {     content string }  func (e *TextEditor) Save() Memento {     return Memento{content: e.content} }  func (e *TextEditor) Restore(m Memento) {     e.content = m.content }
  • Save() 方法用于生成當前狀態的快照。
  • Restore() 方法接受一個備忘錄,把狀態還原。

注意這里用了指針接收者,因為我們要修改結構體內部狀態。


管理多個快照:使用管理者(Caretaker)

如果你想支持撤銷/重做操作,就需要一個地方來保存多個備忘錄。通常的做法是一個切片加上索引管理。

舉個例子:

type Caretaker struct {     history []Memento     index   int }  func (c *Caretaker) Add(m Memento) {     c.history = append(c.history[:c.index+1], m)     c.index++ }  func (c *Caretaker) Undo() bool {     if c.index <= 0 {         return false     }     c.index--     return true }  func (c *Caretaker) redo() bool {     if c.index >= len(c.history)-1 {         return false     }     c.index++     return true }  func (c *Caretaker) Current() Memento {     if len(c.history) == 0 || c.index < 0 {         return Memento{}     }     return c.history[c.index] }

這樣你就可以通過調用 Undo() 和 Redo() 在不同狀態之間切換了。


實際用法示例

組合前面的結構,可以像這樣使用:

editor := &TextEditor{} caretaker := Caretaker{}  editor.content = "第一次內容" caretaker.Add(editor.Save())  editor.content = "第二次內容" caretaker.Add(editor.Save())  // 撤銷一次 caretaker.Undo() editor.Restore(caretaker.Current()) fmt.Println(editor.content) // 輸出:第一次內容

這種方式適合需要頻繁保存狀態并恢復的場景,比如編輯器、游戲存檔、配置管理等。

幾點建議:

  • 如果狀態數據很大,考慮深拷貝或不可變設計避免副作用。
  • 可以限制歷史記錄數量,防止內存占用過高。
  • 備忘錄結構可以序列化后保存到文件或數據庫中,實現持久化。

基本上就這些。不復雜但容易忽略細節,比如并發訪問時的同步問題,或者大對象頻繁保存帶來的性能開銷,這些在實際項目中也需要注意。

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享