新聞中心
大家好,這里是每周都在陪你一起進(jìn)步的網(wǎng)管~!今天繼續(xù)學(xué)習(xí)設(shè)計模式—備忘錄模式

創(chuàng)新互聯(lián)云計算的互聯(lián)網(wǎng)服務(wù)提供商,擁有超過13年的服務(wù)器租用、電信內(nèi)江機房、云服務(wù)器、虛擬主機、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗,已先后獲得國家工業(yè)和信息化部頒發(fā)的互聯(lián)網(wǎng)數(shù)據(jù)中心業(yè)務(wù)許可證。專業(yè)提供云主機、虛擬主機、域名申請、VPS主機、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
備忘錄模式(Memento Pattern)又叫作快照模式(Snapshot Pattern), 或令牌模式(Token Pattern), 指在不破壞封裝的前提下, 捕獲一個對象的內(nèi)部狀態(tài), 并在對象之外保存這個狀態(tài)。 這樣以后就可將該對象恢復(fù)到原先保存的狀態(tài), 屬于行為型設(shè)計模式。
備忘錄模式主要適用于以下應(yīng)用場景。
- 需要保存歷史快照的場景。
- 希望在對象之外保存狀態(tài),且除了自己,其他類對象無法訪問狀態(tài)保存的具體內(nèi)容。
備忘錄模式是一種行為型設(shè)計模式。這種模式允許我們保存對象在某些關(guān)鍵節(jié)點時的必要信息,以便于在適當(dāng)?shù)臅r候可以將之恢復(fù)到之前的狀態(tài)。通常它可以用來幫助設(shè)計撤銷/恢復(fù)操作。
備忘錄模式的類結(jié)構(gòu)
下面是備忘錄模式的類圖,
圖片來自https://refactoringguru.cn/design-patterns/memento,我后面實現(xiàn)的時候不會完全按照這個結(jié)構(gòu)去實現(xiàn),這里先把結(jié)構(gòu)里的各個角色給大家說清楚。
備忘錄模式中主要有這三個角色的類
- Originator(發(fā)起者):Originator是當(dāng)前的基礎(chǔ)對象,它會將自己的狀態(tài)保存進(jìn)備忘錄,此角色可以類比博客系統(tǒng)中的文章對象
- 發(fā)起者中要有保存方法和從備忘錄中恢復(fù)狀態(tài)的方法,保存方法會返回當(dāng)時狀態(tài)組成的備忘錄對象
- Memento(備忘錄) : 存儲著Originator的狀態(tài)的對象,類比理解即為文章對象的不同版本。
- Caretaker(管理人):Caretaker是保存著多條備忘錄的對象,并維護(hù)著備忘錄的索引,在需要的時候會返回相應(yīng)的備忘錄 -- 類比理解為博客系統(tǒng)中的編輯器對象
管理者的保存和恢復(fù)操作,會代理其持有的發(fā)起者對象的保存和恢復(fù)操作,在這些代理方法中會增加對備忘錄對象列表、當(dāng)前備忘錄版本的維護(hù)。
上面這個類圖結(jié)構(gòu)是實現(xiàn)備忘錄模式的最簡單方式,真實使用的時候,Caretaker,Originator、memento 這些角色可以繼續(xù)抽象出對應(yīng)的接口和實現(xiàn)。這里就不搞那么復(fù)雜了,要舉的例子比較簡單,這么一拆顯得這個模式用起來特別費事兒。
其實其他設(shè)計模式也是一樣,學(xué)習(xí)的時候大家知道了它的結(jié)構(gòu)后,在實現(xiàn)應(yīng)用的環(huán)節(jié)不必完完全全按照結(jié)構(gòu)一板一眼地全部進(jìn)行實現(xiàn),有的應(yīng)用場景并不復(fù)雜,能合并的角色可以按需進(jìn)行合并。
應(yīng)用舉例
場景
某線上博客平臺, 需為用戶提供在線編輯文章功能,文章主要包括標(biāo)題 - title 和內(nèi)容 - content等信息。為最大程度防止異常情況導(dǎo)致編輯內(nèi)容的丟失, 需要提供版本暫存和Undo, Redo功能。
"版本暫存"問題可以應(yīng)用備忘錄模式, 將編輯器的狀態(tài)完整保存起來(主要就是編輯內(nèi)容),Undo和Redo的本質(zhì), 是在歷史版本中前后移動把當(dāng)時保存的內(nèi)容加載到文章對象上。
方案設(shè)計
- IEditor: 定義編輯器接口
- EditorMemento: 定義編輯器的備忘錄, 也就是編輯器的內(nèi)部狀態(tài)數(shù)據(jù)模型, 同時也對應(yīng)一個歷史版本
- Editor: 編輯器類, 實現(xiàn)IEditor接口
這個例子里我們把原發(fā)器和管理人兩個角色集中在Editor類型上一起實現(xiàn),例子比較簡單,就沒有單獨實現(xiàn)一個Article類型作為原發(fā)器角色,如果你想完全按照備忘錄模式的結(jié)構(gòu)實現(xiàn),把Title、Content這寫屬性和Save方法抽離到單獨的Article類型上,再讓Editor嵌套組合Article即可。
下面我們根據(jù)UML類圖實現(xiàn)一下這個帶Undo、Redo功能的編輯器。
代碼實現(xiàn)
首先在IEditor 接口里定義編輯器對象要實現(xiàn)的行為
// 編輯器接口定義
type IEditor interface {
Title(title string)
Content(content string)
Save()
Undo() error
Redo() error
Show()
}
接下來定義編輯器的備忘錄, 也就是編輯器的內(nèi)部狀態(tài)數(shù)據(jù)模型, 同時也對應(yīng)一個歷史版本。
"本文使用的完整可運行源碼
去公眾號「網(wǎng)管叨bi叨」發(fā)送【設(shè)計模式】即可領(lǐng)取"
type Memento struct {
title string
content string
createTime int64
}
func newMemento(title string, content string) *Memento {
return &Memento{
title, content, time.Now().Unix(),
}
}
然后是最復(fù)雜的Editor實現(xiàn),它會實現(xiàn)上面IEditor接口中定義的所有行為,其中的Undo、Redo方法即回退、前進(jìn)方法在實現(xiàn)的時候就是依賴的它內(nèi)部記錄的一組Memento對象,通過指向不同的Memento對象來實現(xiàn)回退和前進(jìn)功能。
"本文使用的完整可運行源碼
去公眾號「網(wǎng)管叨bi叨」發(fā)送【設(shè)計模式】即可領(lǐng)取"
// 編輯器類, 實現(xiàn)IEditor接口
type Editor struct {
title string
content string
versions []*Memento
index int
}
func NewEditor() IEditor {
return &Editor{
"", "", make([]*Memento, 0), 0,
}
}
func (editor *Editor) Title(title string) {
editor.title = title
}
func (editor *Editor) Content(content string) {
editor.content = content
}
func (editor *Editor) Save() {
it := newMemento(editor.title, editor.content)
editor.versions = append(editor.versions, it)
editor.index = len(editor.versions) - 1
}
func (editor *Editor) Undo() error {
return editor.load(editor.index - 1)
}
func (editor *Editor) load(i int) error {
size := len(editor.versions)
if size <= 0 {
return errors.New("no history versions")
}
if i < 0 || i >= size {
return errors.New("no more history versions")
}
it := editor.versions[i]
editor.title = it.title
editor.content = it.content
editor.index = i
return nil
}
func (editor *Editor) Redo() error {
return editor.load(editor.index + 1)
}
func (editor *Editor) Show() {
fmt.Printf("MockEditor.Show, title=%s, cnotallow=%s\n", editor.title, editor.content)
}
最后我們來測試一下Editor的版本記錄功能
"本文使用的完整可運行源碼
去公眾號「網(wǎng)管叨bi叨」發(fā)送【設(shè)計模式】即可領(lǐng)取"
func main() {
editor := NewEditor()
// test save()
editor.Title("唐詩")
editor.Content("白日依山盡")
editor.Save()
editor.Title("唐詩 登鸛雀樓")
editor.Content("白日依山盡, 黃河入海流. ")
editor.Save()
editor.Title("唐詩 登鸛雀樓 王之渙")
editor.Content("白日依山盡, 黃河入海流。欲窮千里目, 更上一層樓。")
editor.Save()
// test show()
fmt.Println("-------------Editor 當(dāng)前內(nèi)容-----------")
editor.Show()
fmt.Println("-------------Editor 回退內(nèi)容-----------")
for {
e := editor.Undo()
if e != nil {
break
} else {
editor.Show()
}
}
fmt.Println("-------------Editor 前進(jìn)內(nèi)容-----------")
for {
e := editor.Redo()
if e != nil {
break
} else {
editor.Show()
}
}
}
運行程序后會有類似下面的顯示
分享名稱:Go設(shè)計模式--備忘錄模式,帶暫存的業(yè)務(wù)功能可以參考它來實現(xiàn)
瀏覽路徑:http://m.fisionsoft.com.cn/article/djeiooo.html


咨詢
建站咨詢
