8.9備忘錄模式
8.9.1概念
? 備忘錄模式允許在不暴露對象實現(xiàn)細節(jié)的情況下捕獲和恢復(fù)對象的內(nèi)部狀態(tài)。通過將對象的狀態(tài)封裝在備忘錄對象中,并將備忘錄對象保存在一個管理者對象中,可以在需要時回滾到對象之前的狀態(tài)。
8.9.2場景
? 在現(xiàn)代辦公場景中,備忘錄模式可以應(yīng)用于文檔編輯工具中。以O(shè)ffice工具為例,當(dāng)用戶在云文檔中進行編輯時,系統(tǒng)會自動將當(dāng)前的文檔內(nèi)容保存在一個備忘錄對象中,并將備忘錄對象存儲在云端的服務(wù)器上。每隔一段時間,系統(tǒng)會判斷是否需要保存文檔的狀態(tài),如果需要,則將當(dāng)前的備忘錄對象保存為一個快照,以便日后恢復(fù)文檔的狀態(tài)。
8.9.3優(yōu)勢 / 劣勢
- 提供恢復(fù)機制:當(dāng)用戶有需要時,能夠比較方便地將數(shù)據(jù)恢復(fù)到某個歷史的狀態(tài)
- 實現(xiàn)內(nèi)部封裝:除了創(chuàng)建它的發(fā)起人之外,其他對象都不能夠訪問這些狀態(tài)信息
- 資源消耗大:若需要保存的內(nèi)部狀態(tài)信息過多或者特別頻繁是,將會占用比較大的內(nèi)存資源
- 難以確定保存時間:當(dāng)對象的狀態(tài)發(fā)生改變時,需要判斷是否需要存儲備忘錄
8.9.4備忘錄模式可分為
- 發(fā)起人Originator:需要還原狀態(tài)的那個對象,負責(zé)創(chuàng)建一個備忘錄,并使用備忘錄記錄當(dāng)前時刻的內(nèi)部狀態(tài)
- 備忘錄Memento:存儲發(fā)起人對象的內(nèi)部狀態(tài),它可以包含發(fā)起人的部分或全部狀態(tài)信息,但是對外部是不可見的,只有發(fā)起人能夠訪問備忘錄對象的狀態(tài)
備忘錄有兩個接口,發(fā)起人能夠通過寬接口訪問數(shù)據(jù),管理者只能看到窄接口,并將備忘錄傳遞給其他對象
- 管理者Caretaker:負責(zé)存儲備忘錄對象,但并不了解其內(nèi)部結(jié)構(gòu),管理者可以存儲多個備忘錄對象
- 客戶端:在需要恢復(fù)狀態(tài)時,客戶端可以從管理者哪里獲取備忘錄對象,并將其傳遞給發(fā)起人進行狀態(tài)的恢復(fù)
8.9.5備忘錄模式
package com.technologystatck.designpattern.mode.memorandum;
import java.util.ArrayList;
import java.util.List;
public class Memorandum {
public static void main(String[] args) {
//創(chuàng)建發(fā)起人對象
Originator originator = new Originator();
originator.setState("State 1");
//創(chuàng)建管理者對象
Caretaker caretaker = new Caretaker();
//保存當(dāng)前狀態(tài)
caretaker.addMemento(originator.createMemento());
System.out.println("Current State:"+originator.getState());
//修改狀態(tài)
originator.setState("State 2");
System.out.println("Current State:"+originator.getState());
//再次保存當(dāng)前狀態(tài)
caretaker.addMemento(originator.createMemento());
//恢復(fù)到先前狀態(tài)
originator.restoreFromMemento(caretaker.getMemento(0));
System.out.println("Current State:"+originator.getState());
}
}
//創(chuàng)建發(fā)起人類:可以創(chuàng)建備忘錄對象
class Originator{
//備忘錄的狀態(tài)
private String state;
public void setState(String state){
this.state=state;
}
public String getState(){
return state;
}
//創(chuàng)建備忘錄對象
public Memento createMemento(){
return new Memento(this.state);
}
//通過備忘錄對象恢復(fù)狀態(tài)
public void restoreFromMemento(Memento memento){
state=memento.getState();
}
}
//創(chuàng)建備忘錄類:保存發(fā)起人對象的狀態(tài)
class Memento{
private String state;
//保存發(fā)起人的狀態(tài)
public Memento(String state){
this.state=state;
}
public String getState(){
return state;
}
}
//創(chuàng)建備忘錄管理者類:保存?zhèn)渫泴ο?/span>
class Caretaker{
private List<Memento> mementos=new ArrayList<>();
//添加備忘錄對象
public void addMemento(Memento memento){
mementos.add(memento);
}
//獲取備忘錄對象
public Memento getMemento(int index){
return mementos.get(index);
}
}
8.9.6實戰(zhàn)
8.9.6.1題目描述
小明正在設(shè)計一個簡單的計數(shù)器應(yīng)用,支持增加(Increment)和減少(Decrement)操作,以及撤銷(Undo)和重做(Redo)操作,請你使用備忘錄模式幫他實現(xiàn)。
8.9.6.2輸入描述
輸入包含若干行,每行包含一個字符串,表示計數(shù)器應(yīng)用的操作,操作包括 “Increment”、“Decrement”、“Undo” 和 “Redo”。文章來源:http://www.zghlxwxcb.cn/news/detail-823582.html
8.9.6.3輸出描述
對于每個 “Increment” 和 “Decrement” 操作,輸出當(dāng)前計數(shù)器的值,計數(shù)器數(shù)值從0開始 對于每個 “Undo” 操作,輸出撤銷后的計數(shù)器值。 對于每個 “Redo” 操作,輸出重做后的計數(shù)器值。文章來源地址http://www.zghlxwxcb.cn/news/detail-823582.html
8.9.6.4代碼
package com.technologystatck.designpattern.mode.memorandum;
import java.util.Scanner;
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Counter counter = new Counter();
//處理計數(shù)器應(yīng)用的輸入
while (scanner.hasNext()) {
String operation = scanner.next();
switch (operation) {
case "Increment":
counter.increment();
break;
case "Decrement":
counter.decrement();
break;
case "Undo":
counter.undo();
break;
case "Redo":
counter.redo();
break;
}
System.out.println(counter.getValue());
}
}
}
//備忘錄
class Memento {
//備忘錄的狀態(tài)
private int value;
public Memento(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
//創(chuàng)建人
class Counter {
//表示計數(shù)器的值
private int value;
//撤銷操作
private Stack<Memento> undoStack = new Stack<>();
//重做操作
private Stack<Memento> redoStack = new Stack<>();
//減少計數(shù)器的值
public void increment() {
//執(zhí)行撤銷操作時,需要清除一些無效的備忘錄對象
//這些備忘錄對象失去作用了需要清空
redoStack.clear();
//需要將當(dāng)前狀態(tài)保存在撤銷棧中
undoStack.push(new Memento(value));
//計數(shù)器的值加1
value++;
}
//增加計數(shù)器值
public void decrement() {
//執(zhí)行重做操作時,需要清除一些無效的備忘錄對象
//這些備忘錄對象失去作用了需要清空
redoStack.clear();
//需要將當(dāng)前狀態(tài)保存在撤銷棧中
undoStack.push(new Memento(value));
//計數(shù)器的值加1
value--;
}
/**
* 當(dāng)執(zhí)行撤銷或重做的操作時,都會將相關(guān)的備忘錄對象
* 移動到另一個棧中,保證了操作的一致性
*/
//撤銷操作
public void undo() {
//若撤銷棧不為空,則將當(dāng)前棧頂元素移動到重做棧中,
//并將當(dāng)前棧頂元素的值賦給value變量
if (!undoStack.isEmpty()) {
redoStack.push(new Memento(value));
value = undoStack.pop().getValue();
}
}
//重做操作
public void redo() {
//若重做棧不為空,則將當(dāng)前棧頂元素移動到撤銷棧中
//并將當(dāng)前棧頂元素的值賦給value變量
if (!redoStack.isEmpty()) {
undoStack.push(new Memento(value));
value = redoStack.pop().getValue();
}
}
//獲取value值
public int getValue() {
return value;
}
}
8.9.7總結(jié)
- 優(yōu)點:簡化了原始對象的代碼結(jié)構(gòu),支持撤銷和恢復(fù)操作
- 總結(jié):將對象的狀態(tài)使用?;蚣系男问奖4嫫饋?,當(dāng)需要撤銷或重做時,就記錄當(dāng)前對象的狀態(tài),并將棧或集合中的值取出來
- 場景:適用于需要保證對象內(nèi)部狀態(tài)的封裝和私有性前提下可以輕松地添加新的備忘錄和發(fā)起人以此來實現(xiàn)備份
到了這里,關(guān)于笨蛋學(xué)設(shè)計模式行為型模式-備忘錄模式【22】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!