備忘錄模式用于保存并恢復對象狀態,其核心在于定義備忘錄結構、實現發起人和管理者。1. 定義備忘錄結構體memento,保存關鍵狀態字段content;2. 創建發起人texteditor,實現save()生成快照和restore()恢復狀態;3. 使用管理者caretaker管理多個快照,通過add()添加、undo()撤銷、redo()重做、current()獲取當前快照;4. 實際使用時通過組合上述結構實現內容編輯與狀態切換;5. 建議關注深拷貝、內存限制、序列化及并發性能等問題。
備忘錄模式的核心是保存對象的某個狀態,以便后續可以恢復。在go語言中,雖然沒有類的概念,但通過結構體和接口,我們完全可以實現類似的功能。
這篇文章講的是:如何用golang實現備忘錄模式,讓一個對象的狀態可以被保存并恢復。
定義備忘錄結構
要保存對象狀態,首先得有一個“備忘錄”結構體,用來存儲你想保留的數據。這個結構體應該盡可能輕量,只包含需要保存的狀態字段。
立即學習“go語言免費學習筆記(深入)”;
比如,假設你有一個文本編輯器結構體 TextEditor,你想保存它的內容:
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) // 輸出:第一次內容
這種方式適合需要頻繁保存狀態并恢復的場景,比如編輯器、游戲存檔、配置管理等。
幾點建議:
基本上就這些。不復雜但容易忽略細節,比如并發訪問時的同步問題,或者大對象頻繁保存帶來的性能開銷,這些在實際項目中也需要注意。