備忘錄模式(Memento Pattern)官方的定義是這樣的:
在不破壞封閉的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可將該物件恢復到原先儲存的狀態。它是物件導向的23種設計模式中的一種,屬於行為模式的範圍。
直白點說就是:
我們可以在不暴露更多欄位的前提下,直接將某個物件儲存到其他地方,可以是磁碟,也可以是記憶體。
有些地方也將之稱為快照模式,就是給當前物件做一個快照。
一般我們將備忘錄模式定義為3個組成角色:
1、Originator 發起人,有些人將他翻譯為原發器,我是非常不認同的。
什麼叫原發器?本人查了辭海等線上網站,壓根就沒有這個詞,我非常不人認同最初的譯者,憑感覺隨意造詞。
Originator 查詢了谷歌翻譯(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )
a person who creates or initiates something.
大概可以理解為 創始人或者是最初發起某個事情的人,所以這裡可以理解為驅動、發起生成備忘錄的角色。
2、Memento 備忘錄,用來儲存要儲存物件的內部狀態,也就是快照。
3、Caretaker 負責人 負責儲存和管理備忘錄的。
下面我們寫一個例子,
背景:模仿超級馬里奧,可以吃金幣,移動
主類:
1 package com.example.demo.learn.pattern.behavior.memento; 2 3 import com.alibaba.nacos.shaded.com.google.common.collect.Maps; 4 5 import java.util.Map; 6 7 /** 8 * @discription 9 */ 10 public class RecordSystem { 11 12 private static Map<String, String> recordMap = Maps.newHashMap(); 13 14 public static void saveRecord(MapInfo mapInfo, String index) { 15 recordMap.put(index, mapInfo.saveRecord()); 16 } 17 18 public static MapInfo getRecord(String time) { 19 if (recordMap.containsKey(time)) { 20 return MapInfo.loadRecord(recordMap.get(time)); 21 } 22 return null; 23 } 24 }
遊戲內容類:
1 package com.example.demo.learn.pattern.behavior.memento; 2 3 import com.alibaba.fastjson.JSON; 4 import lombok.Data; 5 6 /** 7 * @discription 8 */ 9 @Data 10 public class MapInfo { 11 private Location marioLocation = new Location(0, 100, 1); 12 private int golden = 0; 13 14 public void touchGolden() { 15 golden++; 16 } 17 18 public void marioMove(int xv, int yv) { 19 int newX = marioLocation.getX() + xv; 20 marioLocation.setX(newX); 21 22 int newY = marioLocation.getY() + yv; 23 marioLocation.setY(newY); 24 } 25 26 //馬里奧調頭 27 public void marioTuneBack() { 28 int forward = marioLocation.getForward() * -1; 29 marioLocation.setX(forward); 30 } 31 32 public String saveRecord() { 33 return JSON.toJSONString(marioLocation) + ";" + golden; 34 } 35 36 public static MapInfo loadRecord(String recordContent) { 37 String[] contents = recordContent.split(";"); 38 MapInfo mapInfo = new MapInfo(); 39 Location marioLocation = JSON.parseObject(contents[0], Location.class); 40 mapInfo.setMarioLocation(marioLocation); 41 mapInfo.setGolden(Integer.valueOf(contents[1])); 42 return mapInfo; 43 } 44 45 public static MapInfo initMap() { 46 MapInfo mapInfo = new MapInfo(); 47 return mapInfo; 48 } 49 }
package com.example.demo.learn.pattern.behavior.memento; import lombok.AllArgsConstructor; import lombok.Data; /** * @discription */ @AllArgsConstructor @Data public class Location { //座標 private int x; //座標 private int y; //方向 -1向左,1向右 private int forward; }
遊戲記錄儲存
1 package com.example.demo.learn.pattern.behavior.memento; 2 3 import com.alibaba.nacos.shaded.com.google.common.collect.Maps; 4 5 import java.util.Map; 6 7 /** 8 * @discription 9 */ 10 public class RecordSystem { 11 12 private static Map<String, String> recordMap = Maps.newHashMap(); 13 14 public static void saveRecord(MapInfo mapInfo, String index) { 15 recordMap.put(index, mapInfo.saveRecord()); 16 } 17 18 public static MapInfo getRecord(String time) { 19 if (recordMap.containsKey(time)) { 20 return MapInfo.loadRecord(recordMap.get(time)); 21 } 22 return null; 23 } 24 }
輸出大概是這樣:
"C:\Program Files\Java\jdk-11\bin\java.exe" "-javaagent:E:\Program Files\JetBrains\IntelliJ IDEA 2023.2\lib\idea_rt.jar=65256:E:\Program Files\JetBrains\IntelliJ IDEA 2023.2\bin" -Dfile.encoding=UTF-8 -classpath E:\code\common\learn-design-pattern\target\classes;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-starter\2.6.15\spring-boot-starter-2.6.15.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot\2.6.15\spring-boot-2.6.15.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-autoconfigure\2.6.15\spring-boot-autoconfigure-2.6.15.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-starter-logging\2.6.15\spring-boot-starter-logging-2.6.15.jar;E:\Maven\learnDesignPattenRepo\ch\qos\logback\logback-classic\1.2.12\logback-classic-1.2.12.jar;E:\Maven\learnDesignPattenRepo\ch\qos\logback\logback-core\1.2.12\logback-core-1.2.12.jar;E:\Maven\learnDesignPattenRepo\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;E:\Maven\learnDesignPattenRepo\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;E:\Maven\learnDesignPattenRepo\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;E:\Maven\learnDesignPattenRepo\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;E:\Maven\learnDesignPattenRepo\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-core\5.3.27\spring-core-5.3.27.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-jcl\5.3.27\spring-jcl-5.3.27.jar;E:\Maven\learnDesignPattenRepo\org\yaml\snakeyaml\1.29\snakeyaml-1.29.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-starter-web\2.6.15\spring-boot-starter-web-2.6.15.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-starter-json\2.6.15\spring-boot-starter-json-2.6.15.jar;E:\Maven\learnDesignPattenRepo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.5\jackson-datatype-jdk8-2.13.5.jar;E:\Maven\learnDesignPattenRepo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.5\jackson-datatype-jsr310-2.13.5.jar;E:\Maven\learnDesignPattenRepo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.5\jackson-module-parameter-names-2.13.5.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-starter-tomcat\2.6.15\spring-boot-starter-tomcat-2.6.15.jar;E:\Maven\learnDesignPattenRepo\org\apache\tomcat\embed\tomcat-embed-core\9.0.75\tomcat-embed-core-9.0.75.jar;E:\Maven\learnDesignPattenRepo\org\apache\tomcat\embed\tomcat-embed-el\9.0.75\tomcat-embed-el-9.0.75.jar;E:\Maven\learnDesignPattenRepo\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.75\tomcat-embed-websocket-9.0.75.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-web\5.3.27\spring-web-5.3.27.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-beans\5.3.27\spring-beans-5.3.27.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-webmvc\5.3.27\spring-webmvc-5.3.27.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-expression\5.3.27\spring-expression-5.3.27.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-test\2.6.15\spring-boot-test-2.6.15.jar;E:\Maven\learnDesignPattenRepo\junit\junit\4.13.2\junit-4.13.2.jar;E:\Maven\learnDesignPattenRepo\org\hamcrest\hamcrest-core\2.2\hamcrest-core-2.2.jar;E:\Maven\learnDesignPattenRepo\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;E:\Maven\learnDesignPattenRepo\org\apache\commons\commons-lang3\3.13.0\commons-lang3-3.13.0.jar;E:\Maven\learnDesignPattenRepo\com\alibaba\nacos\nacos-spring-context\1.1.1\nacos-spring-context-1.1.1.jar;E:\Maven\learnDesignPattenRepo\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-context\5.3.27\spring-context-5.3.27.jar;E:\Maven\learnDesignPattenRepo\com\alibaba\spring\spring-context-support\1.0.11\spring-context-support-1.0.11.jar;E:\Maven\learnDesignPattenRepo\org\projectlombok\lombok\1.18.30\lombok-1.18.30.jar;E:\Maven\learnDesignPattenRepo\com\alibaba\fastjson\1.2.83\fastjson-1.2.83.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-starter-aop\2.6.15\spring-boot-starter-aop-2.6.15.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-aop\5.3.27\spring-aop-5.3.27.jar;E:\Maven\learnDesignPattenRepo\cglib\cglib\3.1\cglib-3.1.jar;E:\Maven\learnDesignPattenRepo\org\ow2\asm\asm\4.2\asm-4.2.jar;E:\Maven\learnDesignPattenRepo\org\springframework\boot\spring-boot-starter-amqp\2.6.15\spring-boot-starter-amqp-2.6.15.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-messaging\5.3.27\spring-messaging-5.3.27.jar;E:\Maven\learnDesignPattenRepo\org\springframework\amqp\spring-rabbit\2.4.12\spring-rabbit-2.4.12.jar;E:\Maven\learnDesignPattenRepo\org\springframework\amqp\spring-amqp\2.4.12\spring-amqp-2.4.12.jar;E:\Maven\learnDesignPattenRepo\org\springframework\retry\spring-retry\1.3.4\spring-retry-1.3.4.jar;E:\Maven\learnDesignPattenRepo\com\rabbitmq\amqp-client\5.13.1\amqp-client-5.13.1.jar;E:\Maven\learnDesignPattenRepo\org\springframework\spring-tx\5.3.27\spring-tx-5.3.27.jar;E:\Maven\learnDesignPattenRepo\org\aspectj\aspectjweaver\1.9.7\aspectjweaver-1.9.7.jar;E:\Maven\learnDesignPattenRepo\com\alibaba\nacos\nacos-client\2.2.0\nacos-client-2.2.0.jar;E:\Maven\learnDesignPattenRepo\com\alibaba\nacos\nacos-auth-plugin\2.2.0\nacos-auth-plugin-2.2.0.jar;E:\Maven\learnDesignPattenRepo\com\alibaba\nacos\nacos-encryption-plugin\2.2.0\nacos-encryption-plugin-2.2.0.jar;E:\Maven\learnDesignPattenRepo\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;E:\Maven\learnDesignPattenRepo\com\fasterxml\jackson\core\jackson-core\2.13.5\jackson-core-2.13.5.jar;E:\Maven\learnDesignPattenRepo\com\fasterxml\jackson\core\jackson-databind\2.13.5\jackson-databind-2.13.5.jar;E:\Maven\learnDesignPattenRepo\com\fasterxml\jackson\core\jackson-annotations\2.13.5\jackson-annotations-2.13.5.jar;E:\Maven\learnDesignPattenRepo\org\apache\httpcomponents\httpasyncclient\4.1.5\httpasyncclient-4.1.5.jar;E:\Maven\learnDesignPattenRepo\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;E:\Maven\learnDesignPattenRepo\org\apache\httpcomponents\httpcore-nio\4.4.16\httpcore-nio-4.4.16.jar;E:\Maven\learnDesignPattenRepo\org\apache\httpcomponents\httpclient\4.5.14\httpclient-4.5.14.jar;E:\Maven\learnDesignPattenRepo\io\prometheus\simpleclient\0.12.0\simpleclient-0.12.0.jar;E:\Maven\learnDesignPattenRepo\io\prometheus\simpleclient_tracer_otel\0.12.0\simpleclient_tracer_otel-0.12.0.jar;E:\Maven\learnDesignPattenRepo\io\prometheus\simpleclient_tracer_common\0.12.0\simpleclient_tracer_common-0.12.0.jar;E:\Maven\learnDesignPattenRepo\io\prometheus\simpleclient_tracer_otel_agent\0.12.0\simpleclient_tracer_otel_agent-0.12.0.jar com.example.demo.learn.pattern.behavior.memento.PatternMain 16:10:40.045 [main] WARN com.example.demo.learn.pattern.behavior.memento.PatternMain - 存檔中。。。 16:10:40.173 [main] WARN com.example.demo.learn.pattern.behavior.memento.PatternMain - 1號存檔已完成。。。 16:10:40.173 [main] WARN com.example.demo.learn.pattern.behavior.memento.PatternMain (防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )- 存檔中。。。 16:10:40.173 [main] WARN com.example.demo.learn.pattern.behavior.memento.PatternMain - 2號存檔已完成。。。 16:10:40.173 [main] WARN com.example.demo.learn.pattern.behavior.memento.PatternMain - 讀檔中。。。 16:10:40.192 [main] WARN com.example.demo.learn.pattern.behavior.memento.PatternMain - 1號讀檔已完成。。。 Process finished with exit code 0
在這個例子中 MapInfo 擁有了所有內部狀態屬性,但是並不直接暴露出來,我們透過它的save介面,來獲取物件的所有狀態。
這個例子中它負責發起資料的儲存,充當了Originator的角色;
而RecordSystem類,負責管理和儲存備忘錄屬於caretaker角色。
RecordSystem類中的 recordMap,負責充當備忘錄的角色,也就是儲存快照的物件;