色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

實踐GoF的23種設計模式:備忘錄模式

元閏子的邀請 ? 來源:元閏子的邀請 ? 2023-11-25 09:05 ? 次閱讀

簡介

相對于代理模式、工廠模式等設計模式,備忘錄模式(Memento)在我們日常開發中出鏡率并不高,除了應用場景的限制之外,另一個原因,可能是備忘錄模式 UML 結構的幾個概念比較晦澀難懂,難以映射到代碼實現中。比如 Originator(原發器)和 Caretaker(負責人),從字面上很難看出它們在模式中的職責。

但從定義來看,備忘錄模式又是簡單易懂的,GoF 對備忘錄模式的定義如下:

Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.

也即,在不破壞封裝的前提下,捕獲一個對象的內部狀態,并在該對象之外進行保存,以便在未來將對象恢復到原先保存的狀態。

從定義上看,備忘錄模式有幾個關鍵點:封裝、保存、恢復。

對狀態的封裝,主要是為了未來狀態修改或擴展時,不會引發霰彈式修改;保存和恢復則是備忘錄模式的主要特點,能夠對當前對象的狀態進行保存,并能夠在未來某一時刻恢復出來。

現在,在回過頭來看備忘錄模式的 3 個角色就比較好理解了:

Memento(備忘錄):是對狀態的封裝,可以是struct,也可以是interface。

Originator(原發器):備忘錄的創建者,備忘錄里存儲的就是 Originator 的狀態。

Caretaker(負責人):負責對備忘錄的保存和恢復,無須知道備忘錄中的實現細節。

UML 結構

1d4190e0-8b2d-11ee-939d-92fbcf53809c.png

場景上下文

在前文【Go實現】實踐GoF的23種設計模式:命令模式我們提到,在簡單的分布式應用系統(示例代碼工程)中,db 模塊用來存儲服務注冊信息和系統監控數據。其中,服務注冊信息拆成了profiles和regions兩個表,在服務發現的業務邏輯中,通常需要同時操作兩個表,為了避免兩個表數據不一致的問題,db 模塊需要提供事務功能:

1d75d79c-8b2d-11ee-939d-92fbcf53809c.png

事務的核心功能之一是,當其中某個語句執行失敗時,之前已執行成功的語句能夠回滾,前文我們已經介紹如何基于命令模式搭建事務框架,下面我們將重點介紹,如何基于備忘錄模式實現失敗回滾的功能。

代碼實現

//demo/db/transaction.go
packagedb

//Command執行數據庫操作的命令接口,同時也是備忘錄接口
//關鍵點1:定義Memento接口,其中Exec方法相當于UML圖中的SetState方法,調用后會將狀態保存至Db中
typeCommandinterface{
Exec()error//Exec執行insert、update、delete命令
Undo()//Undo回滾命令
setDb(dbDb)//SetDb設置關聯的數據庫
}

//關鍵點2:定義Originator,在本例子中,狀態都是存儲在Db對象中
typeDbinterface{...}

//TransactionDb事務實現,事務接口的調用順序為begin->exec->exec>...->commit
//關鍵點3:定義Caretaker,Transaction里實現了對語句的執行(Do)和回滾(Undo)操作
typeTransactionstruct{
namestring
//關鍵點4:在Caretaker(Transaction)中引用Originator(Db)對象,用于后續對其狀態的保存和恢復
dbDb
//注意,這里的cmds并非備忘錄列表,真正的history在Commit方法中
cmds[]Command
}
//Begin開啟一個事務
func(t*Transaction)Begin(){
t.cmds=make([]Command,0)
}
//Exec在事務中執行命令,先緩存到cmds隊列中,等commit時再執行
func(t*Transaction)Exec(cmdCommand)error{
ift.cmds==nil{
returnErrTransactionNotBegin
}
cmd.setDb(t.db)
t.cmds=append(t.cmds,cmd)
returnnil
}
//Commit提交事務,執行隊列中的命令,如果有命令失敗,則回滾后返回錯誤
func(t*Transaction)Commit()error{
//關鍵點5:定義備忘錄列表,用于保存某一時刻的系統狀態
history:=&cmdHistory{history:make([]Command,0,len(t.cmds))}
for_,cmd:=ranget.cmds{
//關鍵點6:執行Do方法
iferr:=cmd.Exec();err!=nil{
//關鍵點8:當Do方法執行失敗時,則進行Undo操作,根據備忘錄history中的狀態進行回滾
history.rollback()
returnerr
}
//關鍵點7:如果Do方法執行成功,則將狀態(cmd)保存在備忘錄history中
history.add(cmd)
}
returnnil
}
//cmdHistory命令執行歷史
typecmdHistorystruct{
history[]Command
}
func(c*cmdHistory)add(cmdCommand){
c.history=append(c.history,cmd)
}

func(c*cmdHistory)rollback(){
fori:=len(c.history)-1;i>=0;i--{
c.history[i].Undo()
}
}

//InsertCmd插入命令
//關鍵點9:定義具體的備忘錄類,實現Memento接口
typeInsertCmdstruct{
dbDb
tableNamestring
primaryKeyinterface{}
newRecordinterface{}
}

func(i*InsertCmd)Exec()error{
returni.db.Insert(i.tableName,i.primaryKey,i.newRecord)
}
func(i*InsertCmd)Undo(){
i.db.Delete(i.tableName,i.primaryKey)
}
func(i*InsertCmd)setDb(dbDb){
i.db=db
}

//UpdateCmd更新命令
typeUpdateCmdstruct{...}
//DeleteCmd刪除命令
typeDeleteCmdstruct{...}

客戶端可以這么使用:

funcclient(){
transaction:=db.CreateTransaction("register"+profile.Id)
transaction.Begin()
rcmd:=db.NewUpdateCmd(regionTable).WithPrimaryKey(profile.Region.Id).WithRecord(profile.Region)
transaction.Exec(rcmd)
pcmd:=db.NewUpdateCmd(profileTable).WithPrimaryKey(profile.Id).WithRecord(profile.ToTableRecord())
transaction.Exec(pcmd)
iferr:=transaction.Commit();err!=nil{
return...
}
return...
}

這里并沒有完全按照標準的備忘錄模式 UML 進行實現,但本質是一樣的,總結起來有以下幾個關鍵點:

定義抽象備忘錄 Memento 接口,這里為Command接口。Command的實現是具體的數據庫執行操作,并且存有對應的回滾操作,比如InsertCmd為“插入”操作,其對應的回滾操作為“刪除”,我們保存的狀態就是“刪除”這一回滾操作。

定義 Originator 結構體/接口,這里為Db接口。備忘錄Command記錄的就是它的狀態。

定義 Caretaker 結構體/接口,這里為Transaction結構體。Transaction采用了延遲執行的設計,當調用Exec方法時只會將命令緩存到cmds隊列中,等到調用Commit方法時才會執行。

在 Caretaker 中引用 Originator 對象,用于后續對其狀態的保存和恢復。這里為Transaction聚合了Db。

在 Caretaker 中定義備忘錄列表,用于保存某一時刻的系統狀態。這里為在Transaction.Commit方法中定義了cmdHistory對象,保存一直執行成功的Command。

執行 Caretaker 具體的業務邏輯,這里為在Transaction.Commit中調用Command.Exec方法,執行具體的數據庫操作命令。

業務邏輯執行成功后,保存當前的狀態。這里為調用cmdHistory.add方法將Command保存起來。

如果業務邏輯執行失敗,則恢復到原來的狀態。這里為調用cmdHistory.rollback方法,反向執行已執行成功的Command的Undo方法進行狀態恢復。

根據具體的業務需要,定義具體的備忘錄,這里定義了InsertCmd、UpdateCmd和DeleteCmd。

擴展

MySQL 的 undo log 機制

MySQL 的undo log(回滾日志)機制本質上用的就是備忘錄模式的思想,前文中Transaction回滾機制實現的方法參考的就是 undo log 機制。

undo log 原理是,在提交事務之前,會把該事務對應的回滾操作(狀態)先保存到 undo log 中,然后再提交事務,當出錯的時候 MySQL 就可以利用 undo log 來回滾事務,即恢復原先的記錄值。

比如,執行一條插入語句:

insertintoregion(id,name)values(1,"beijing");

那么,寫入到 undo log 中對應的回滾語句為:

deletefromregionwhereid=1;

當執行一條語句失敗,需要回滾時,MySQL 就會從讀取對應的回滾語句來執行,從而將數據恢復至事務提交之前的狀態。undo log 是 MySQL 實現事務回滾和多版本控制(MVCC)的根基。

典型應用場景

事務回滾。事務回滾的一種常見實現方法是 undo log,其本質上用的就是備忘錄模式。

系統快照(Snapshot)。多版本控制的用法,保存某一時刻的系統狀態快照,以便在將來能夠恢復。

撤銷功能。比如 Microsoft Offices 這類的文檔編輯軟件的撤銷功能。

優缺點

優點

提供了一種狀態恢復的機制,讓系統能夠方便地回到某個特定狀態下。

實現了對狀態的封裝,能夠在不破壞封裝的前提下實現狀態的保存和恢復。

缺點

資源消耗大。系統狀態的保存意味著存儲空間的消耗,本質上是空間換時間的策略。undo log 是一種折中方案,保存的狀態并非某一時刻數據庫的所有數據,而是一條反操作的 SQL 語句,存儲空間大大減少。

并發安全。在多線程場景,實現備忘錄模式時,要注意在保證狀態的不變性,否則可能會有并發安全問題。

與其他模式的關聯

在實現 Undo/Redo 操作時,你通常需要同時使用備忘錄模式與命令模式。

另外,當你需要遍歷備忘錄對象中的成員時,通常會使用迭代器模式,以防破壞對象的封裝。

文章配圖

可以在用Keynote畫出手繪風格的配圖中找到文章的繪圖方法。






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • UML
    UML
    +關注

    關注

    0

    文章

    122

    瀏覽量

    30858
  • MySQL
    +關注

    關注

    1

    文章

    804

    瀏覽量

    26528
  • MVCC
    +關注

    關注

    0

    文章

    13

    瀏覽量

    1465

原文標題:【Go實現】實踐GoF的23種設計模式:備忘錄模式

文章出處:【微信號:yuanrunzi,微信公眾號:元閏子的邀請】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    HarmonyOS開發實例:【手機備忘錄

    基于用戶首選項,實現了備忘錄新增、更新、刪除以及查找等功能。
    的頭像 發表于 04-18 21:40 ?791次閱讀
    HarmonyOS開發實例:【手機<b class='flag-5'>備忘錄</b>】

    PostgreSQL操作備忘錄

    PostgreSQL 操作備忘錄
    發表于 05-23 08:48

    UDS診斷命令備忘錄

    UDS實踐性強,邏輯復雜,很多服務非要體驗過一次才能理解,導致包括我在內的初學者感覺晦澀難懂,不明覺厲,因此將自己的理解寫下來、整理下來,與君共勉。零、UDS診斷命令備忘錄一、簡介UDS
    發表于 08-26 16:09

    怎樣去搭建一基于XR806的開源桌面備忘錄

    本人計劃懟一個開源桌面備忘錄/天氣預報/相冊的項目基于XR806,同時學習鴻蒙操作系統獲得暈哥贈送的開發板和芯片,目前處于環境搭建階段看起來這個芯片玩的人比較少,目前遇到了問題,不知道如何解決,希望
    發表于 12-28 06:52

    23基本的設計模式總結

    一樣。?提到設計模式,不得不感謝GoF(***,四人組),他們1995年出版的《設計模式》一書,第一次將設計模式提升到理論高度,并將之規范化。書中一共總結了
    發表于 03-01 06:08

    全球半導體聯盟與中國半導體行業簽署合作備忘錄

    全球半導體聯盟與中國半導體行業簽署合作備忘錄 全球半導體聯盟(GSA)與中國半導體行業協會(CSIA)在蘇州聯合申明簽署合作備忘錄。此次合作將為促
    發表于 09-24 08:17 ?698次閱讀

    戴姆勒與百度簽署諒解備忘錄

    7月25日,奔馳母公司戴姆勒與百度簽署諒解備忘錄,深化雙方在自動駕駛和車聯網等領域的戰略合作。
    的頭像 發表于 07-28 09:53 ?2718次閱讀

    23java設計模式

    JAVA的設計模式經前人總結可以分為23 設計模式根據使用類型可以分為三: 1、創建模式
    發表于 09-23 15:17 ?1次下載

    實踐GoF23設計模式:命令模式簡介

    因此,我們需要對請求進行抽象,將上下文信息封裝到請求對象里,這其實就是命令模式,而該請求對象就是 Command。
    的頭像 發表于 01-13 16:36 ?760次閱讀

    設計模式備忘錄設計模式

    備忘錄設計模式(Memento Design Pattern)是一行為型設計模式,它的主要目的是在不破壞對象封裝性的前提下,捕捉和保存一個對象的內部狀態
    的頭像 發表于 06-06 11:19 ?798次閱讀

    設計模式行為型:備忘錄模式

    備忘錄模式(Memento Pattern)保存一個對象的某個狀態,以便在適當的時候恢復對象。備忘錄模式屬于行為型模式。
    的頭像 發表于 06-07 11:16 ?852次閱讀
    設計<b class='flag-5'>模式</b>行為型:<b class='flag-5'>備忘錄</b><b class='flag-5'>模式</b>

    新思科技同越南政府簽署諒解備忘錄

    在越南總理范明政訪美期間,新思科技與越南國家創新中心(nic)簽署了關于培養越南集成電路設計人才的諒解備忘錄,支持nic成立芯片設計孵化中心。另外,新思科技與越南信息通訊部下屬的信息通信技術產業公司簽訂了支援越南半導體產業發展的諒解備忘錄。
    的頭像 發表于 09-20 10:56 ?1550次閱讀

    實踐GoF23設計模式:解釋器模式

    解釋器模式(Interpreter Pattern)應該是 GoF23 設計模式中使用頻率最少的一
    的頭像 發表于 04-01 11:01 ?689次閱讀
    <b class='flag-5'>實踐</b><b class='flag-5'>GoF</b>的<b class='flag-5'>23</b><b class='flag-5'>種</b>設計<b class='flag-5'>模式</b>:解釋器<b class='flag-5'>模式</b>

    蘋果iOS 18將支持語音備忘錄及數學符號顯示

    首先是語音備忘錄功能。據悉,蘋果有意在iOS 18系統中加入此項功能,使iPhone用戶能夠便捷地錄制音頻文件,并將其直接嵌入至備忘錄之中。
    的頭像 發表于 04-18 11:14 ?519次閱讀

    億緯鋰能與馬來西亞拉曼理工大學簽署合作備忘錄

    備忘錄的簽署,旨在通過產學聯合,搭建教育與產業融合的發展框架,推動實踐性人才培養,促進雙方資源共享、優勢互補。
    的頭像 發表于 10-24 10:30 ?222次閱讀
    主站蜘蛛池模板: jizzjizz3d动漫| 麻豆精品无码久久久久久久久| 一二三四在线观看韩国| 免费一区在线观看| 国产亚洲精品高清视频免费| 99er久久国产精品在线| 亚洲国产高清视频在线观看| 欧美 日韩 亚洲 在线| 激情床戏视频片段有叫声| YIN荡的老师系列第6部分视频| 亚洲婷婷天堂综合国产剧情| 日韩娇小性hd| 美女脱得只剩皮肤| 国内精品久久影视免费| 高清 仑乱 一级 a| 97视频在线观看免费视频| 亚洲免费视频在线| 网友自拍偷拍| 人人舔人人爱| 嗯呐啊唔高H兽交| 久久人人玩人妻潮喷内射人人| 国产人妻人伦精品9| 成人国产精品玖玖热色欲| 99精品国产在热| 中文字幕在线视频网站| 亚洲免费福利在线视频| 午夜阳光影院在线观看视频| 日韩一区二区三区四区区区 | 久久精品视频15人人爱在线直播| 动漫美女脱小内内露尿口| 99久久国产露脸精品麻豆| 囯产少妇BBBBBB高潮喷水一| 日本 稀土矿| 热の中文 AV天堂| 欧美z000z猪| 观赏女性排尿| 成人免费视频在线播放| aaa级黄影片| 97国产人妻精品无码AV在线| 2019午夜福利757视频第12集| 正在播放一区二区|