深圳建設(shè)公司網(wǎng)站/優(yōu)化推廣網(wǎng)站排名
設(shè)計(jì)模式-備忘錄模式(Memento)
- 一、備忘錄模式概述
- 1.1 什么是備忘錄模式
- 1.2 簡(jiǎn)單實(shí)現(xiàn)備忘錄模式
- 1.3 使用備忘錄模式的注意事項(xiàng)
- 二、備忘錄模式的用途
- 三、備忘錄模式實(shí)現(xiàn)方式
- 3.1 基于數(shù)組的備忘錄實(shí)現(xiàn)方式
- 3.2 基于集合的備忘錄實(shí)現(xiàn)方式
- 3.3 基于HashMap的備忘錄實(shí)現(xiàn)方式
- 3.4 基于序列化的備忘錄實(shí)現(xiàn)方式
一、備忘錄模式概述
1.1 什么是備忘錄模式
備忘錄模式(Memento Pattern)是一種行為型設(shè)計(jì)模式,它允許你捕獲對(duì)象的內(nèi)部狀態(tài),并在需要時(shí)恢復(fù)該狀態(tài),而無需暴露該對(duì)象的實(shí)現(xiàn)細(xì)節(jié)。所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣,以后就可以將該對(duì)象恢復(fù)到原先保存的狀態(tài)。
這種模式的名字可能對(duì)一些人來說稍微有點(diǎn)陌生,但其另一個(gè)名字快照模式可能會(huì)讓人覺得更為熟悉。備忘錄模式的適用場(chǎng)景包括:需要保存和恢復(fù)數(shù)據(jù)的場(chǎng)景,例如,編輯文檔時(shí)需要撤銷操作;需要避免重復(fù)計(jì)算的場(chǎng)景,例如,斐波那契數(shù)列;以及需要將一個(gè)對(duì)象的狀態(tài)作為參數(shù)傳遞給其他對(duì)象的場(chǎng)景,例如,從數(shù)據(jù)庫中查詢數(shù)據(jù)。
1.2 簡(jiǎn)單實(shí)現(xiàn)備忘錄模式
備忘錄模式是一種行為型設(shè)計(jì)模式,它允許在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣,以后就可以將該對(duì)象恢復(fù)到原先保存的狀態(tài)。
下面是一個(gè)簡(jiǎn)單的Java實(shí)現(xiàn)備忘錄模式的例子:
首先,我們創(chuàng)建一個(gè)原始類(Originator):
public class Originator {private String state;public void setState(String state) {this.state = state;}public String getState() {return state;}public Memento saveStateToMemento() {return new Memento(state);}public void getStateFromMemento(Memento memento) {state = memento.getState();}
}
然后,我們創(chuàng)建一個(gè)備忘錄類(Memento):
public class Memento {private String state;public Memento(String state) {this.state = state;}public String getState() {return state;}
}
接下來,我們創(chuàng)建一個(gè)負(fù)責(zé)管理備忘錄的類(Caretaker):
import java.util.ArrayList;
import java.util.List;public class Caretaker {private List<Memento> mementoList = new ArrayList<>();public void add(Memento state) {mementoList.add(state);}public Memento get(int index) {return mementoList.get(index);}
}
最后,我們?cè)谥骱瘮?shù)中測(cè)試備忘錄模式:
public class Main {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState("狀態(tài)1");caretaker.add(originator.saveStateToMemento());originator.setState("狀態(tài)2");caretaker.add(originator.saveStateToMemento());originator.setState("狀態(tài)3");caretaker.add(originator.saveStateToMemento());System.out.println("當(dāng)前狀態(tài): " + originator.getState());originator.getStateFromMemento(caretaker.get(0));System.out.println("恢復(fù)后的狀態(tài): " + originator.getState());}
}
運(yùn)行結(jié)果:
當(dāng)前狀態(tài): 狀態(tài)3
恢復(fù)后的狀態(tài): 狀態(tài)1
1.3 使用備忘錄模式的注意事項(xiàng)
-
1、備忘錄的保存和使用必須在同一個(gè)上下文中,不能將備忘錄傳遞給其他對(duì)象。如果需要傳遞備忘錄,可以使用Caretaker類來管理備忘錄。
-
2、備忘錄對(duì)象需要保存原始對(duì)象的內(nèi)部狀態(tài),因此備忘錄對(duì)象應(yīng)該與原始對(duì)象具有相同的屬性和方法。但是,備忘錄對(duì)象不應(yīng)該包含任何業(yè)務(wù)邏輯或行為。
-
3、如果原始對(duì)象的內(nèi)部狀態(tài)被修改,備忘錄對(duì)象也需要相應(yīng)地更新。因此,在保存?zhèn)渫浿?#xff0c;需要先調(diào)用原始對(duì)象的saveStateToMemento()方法。
-
4、如果需要恢復(fù)原始對(duì)象的內(nèi)部狀態(tài),可以使用getStateFromMemento()方法。但是,需要注意的是,恢復(fù)后的狀態(tài)可能不是最新的狀態(tài),因?yàn)樵紝?duì)象可能在恢復(fù)狀態(tài)之后又進(jìn)行了修改。
-
5、備忘錄模式適用于那些需要保存和恢復(fù)狀態(tài)的場(chǎng)景,但不適用于所有場(chǎng)景。如果只需要保存和恢復(fù)單個(gè)狀態(tài),可以使用簡(jiǎn)單變量來實(shí)現(xiàn);如果需要保存和恢復(fù)多個(gè)狀態(tài),可以使用數(shù)據(jù)結(jié)構(gòu)(如數(shù)組或列表)來管理備忘錄對(duì)象。
二、備忘錄模式的用途
-
1、備忘錄模式主要用于保存和恢復(fù)對(duì)象的狀態(tài),以便在需要時(shí)可以恢復(fù)到先前的狀態(tài)。這種模式通常用于以下情況:
-
2、撤銷操作:當(dāng)一個(gè)操作序列可以被撤銷時(shí),可以使用備忘錄模式來保存每個(gè)操作的結(jié)果,以便在需要時(shí)進(jìn)行撤銷。
-
3、跨層傳遞參數(shù):當(dāng)一個(gè)對(duì)象需要將其狀態(tài)傳遞給另一個(gè)對(duì)象時(shí),可以使用備忘錄模式將該對(duì)象的狀態(tài)保存在一個(gè)備忘錄中,然后將備忘錄傳遞給另一個(gè)對(duì)象。
-
4、避免重復(fù)計(jì)算:當(dāng)一個(gè)對(duì)象的計(jì)算成本很高時(shí),可以使用備忘錄模式來保存其中間結(jié)果,以便在需要時(shí)可以直接使用這些結(jié)果,而不必重新計(jì)算它們。
-
5、測(cè)試和維護(hù):當(dāng)需要對(duì)一個(gè)對(duì)象進(jìn)行單元測(cè)試或維護(hù)時(shí),可以使用備忘錄模式來保存其當(dāng)前狀態(tài),以便在測(cè)試或維護(hù)完成后可以恢復(fù)到先前的狀態(tài)。
三、備忘錄模式實(shí)現(xiàn)方式
3.1 基于數(shù)組的備忘錄實(shí)現(xiàn)方式
基于數(shù)組的備忘錄實(shí)現(xiàn)方式可以通過以下步驟完成:
創(chuàng)建一個(gè)類,該類包含一個(gè)用于保存狀態(tài)的數(shù)組。
在類中定義一個(gè)方法,該方法將對(duì)象的狀態(tài)保存到數(shù)組中。
在類中定義另一個(gè)方法,該方法從數(shù)組中恢復(fù)對(duì)象的狀態(tài)。
在需要保存和恢復(fù)狀態(tài)的地方調(diào)用相應(yīng)的方法。
以下是一個(gè)簡(jiǎn)單的示例代碼:
public class Memento {private int[] state;public Memento(int[] state) {this.state = state;}public int[] getState() {return state;}
}public class Originator {private int[] state;public void setState(int[] state) {this.state = state;}public int[] getState() {return state;}public Memento saveStateToMemento() {return new Memento(state);}public void getStateFromMemento(Memento memento) {state = memento.getState();}
}public class Caretaker {private List<Memento> mementos = new ArrayList<>();public void add(Memento state) {mementos.add(state);}public Memento get(int index) {return mementos.get(index);}
}public class Main {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState(new int[]{1, 2, 3});caretaker.add(originator.saveStateToMemento());originator.setState(new int[]{4, 5, 6});caretaker.add(originator.saveStateToMemento());originator.getStateFromMemento(caretaker.get(0)); // 恢復(fù)到第一個(gè)狀態(tài)System.out.println(Arrays.toString(originator.getState())); // 輸出 [1, 2, 3]}
}
在這個(gè)示例中,我們創(chuàng)建了一個(gè)Originator類來表示原始對(duì)象,一個(gè)Memento類來表示備忘錄,一個(gè)Caretaker類來管理備忘錄。在Main類的main方法中,我們創(chuàng)建了Originator和Caretaker對(duì)象,并使用它們來保存和恢復(fù)對(duì)象的狀態(tài)。
3.2 基于集合的備忘錄實(shí)現(xiàn)方式
基于集合的備忘錄實(shí)現(xiàn)方式可以通過以下步驟完成:
創(chuàng)建一個(gè)類,該類包含一個(gè)用于保存狀態(tài)的集合。
在類中定義一個(gè)方法,該方法將對(duì)象的狀態(tài)添加到集合中。
在類中定義另一個(gè)方法,該方法從集合中恢復(fù)對(duì)象的狀態(tài)。
在需要保存和恢復(fù)狀態(tài)的地方調(diào)用相應(yīng)的方法。
以下是一個(gè)簡(jiǎn)單的示例代碼:
import java.util.ArrayList;
import java.util.List;public class Memento {private List<String> state;public Memento() {state = new ArrayList<>();}public void addState(String state) {this.state.add(state);}public String getState(int index) {return state.get(index);}
}public class Originator {private List<String> states;public Originator() {states = new ArrayList<>();}public void setState(String state) {states.add(state);}public String getState() {return states.get(states.size() - 1);}public Memento saveStateToMemento() {Memento memento = new Memento();memento.addState(getState());return memento;}public void getStateFromMemento(Memento memento) {int index = states.size() - 1;setState(memento.getState(index));}
}public class Caretaker {private List<Memento> mementos;public Caretaker() {mementos = new ArrayList<>();}public void add(Memento memento) {mementos.add(memento);}public Memento get(int index) {return mementos.get(index);}
}public class Main {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState("狀態(tài)1");caretaker.add(originator.saveStateToMemento());originator.setState("狀態(tài)2");caretaker.add(originator.saveStateToMemento());originator.getStateFromMemento(caretaker.get(0)); // 恢復(fù)到第一個(gè)狀態(tài)System.out.println(originator.getState()); // 輸出 "狀態(tài)1"}
}
在這個(gè)示例中,我們創(chuàng)建了一個(gè)Memento類來表示備忘錄,一個(gè)Originator類來表示原始對(duì)象,一個(gè)Caretaker類來管理備忘錄。在Main類的main方法中,我們創(chuàng)建了Originator和Caretaker對(duì)象,并使用它們來保存和恢復(fù)對(duì)象的狀態(tài)。
3.3 基于HashMap的備忘錄實(shí)現(xiàn)方式
基于HashMap的備忘錄實(shí)現(xiàn)方式可以通過以下步驟完成:
創(chuàng)建一個(gè)類,該類包含一個(gè)用于保存狀態(tài)的HashMap。
在類中定義一個(gè)方法,該方法將對(duì)象的狀態(tài)添加到HashMap中。
在類中定義另一個(gè)方法,該方法從HashMap中恢復(fù)對(duì)象的狀態(tài)。
在需要保存和恢復(fù)狀態(tài)的地方調(diào)用相應(yīng)的方法。
以下是一個(gè)簡(jiǎn)單的示例代碼:
import java.util.HashMap;public class Memento {private HashMap<String, Object> stateMap;public Memento() {stateMap = new HashMap<>();}public void addState(String key, Object value) {stateMap.put(key, value);}public Object getState(String key) {return stateMap.get(key);}
}public class Originator {private String state;public void setState(String state) {this.state = state;}public String getState() {return state;}public Memento saveStateToMemento() {Memento memento = new Memento();memento.addState("state", state);return memento;}public void getStateFromMemento(Memento memento) {state = (String) memento.getState("state");}
}public class Caretaker {private ArrayList<Memento> mementoList;public Caretaker() {mementoList = new ArrayList<>();}public void addMemento(Memento memento) {mementoList.add(memento);}public Memento getMemento(int index) {return mementoList.get(index);}
}public class Main {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState("狀態(tài)1");caretaker.addMemento(originator.saveStateToMemento());originator.setState("狀態(tài)2");caretaker.addMemento(originator.saveStateToMemento());originator.setState((String) caretaker.getMemento(0).getState("state"));System.out.println("恢復(fù)后的狀態(tài): " + originator.getState()); // 輸出 "恢復(fù)后的狀態(tài): 狀態(tài)1"}
}
在這個(gè)示例中,我們創(chuàng)建了一個(gè)Memento類來表示備忘錄,一個(gè)Originator類來表示原始對(duì)象,一個(gè)Caretaker類來管理備忘錄。在Main類的main方法中,我們創(chuàng)建了Originator和Caretaker對(duì)象,并使用它們來保存和恢復(fù)對(duì)象的狀態(tài)。
3.4 基于序列化的備忘錄實(shí)現(xiàn)方式
基于序列化的備忘錄實(shí)現(xiàn)方式可以通過以下步驟完成:
創(chuàng)建一個(gè)類,該類包含一個(gè)用于保存狀態(tài)的私有成員變量。
為該類添加一個(gè)構(gòu)造函數(shù),用于初始化私有成員變量。
為該類添加一個(gè)序列化方法,用于將對(duì)象的狀態(tài)保存到文件中。
為該類添加一個(gè)反序列化方法,用于從文件中恢復(fù)對(duì)象的狀態(tài)。
在需要保存和恢復(fù)狀態(tài)的地方調(diào)用相應(yīng)的序列化和反序列化方法。
以下是一個(gè)簡(jiǎn)單的示例代碼:
import java.io.*;class Memento implements Serializable {private String state;public Memento(String state) {this.state = state;}public String getState() {return state;}public void setState(String state) {this.state = state;}public void saveToFile(String fileName) {try {FileOutputStream fos = new FileOutputStream(fileName);ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(this);oos.close();fos.close();} catch (IOException e) {e.printStackTrace();}}public static Memento restoreFromFile(String fileName) {Memento memento = null;try {FileInputStream fis = new FileInputStream(fileName);ObjectInputStream ois = new ObjectInputStream(fis);memento = (Memento) ois.readObject();ois.close();fis.close();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}return memento;}
}public class Main {public static void main(String[] args) {Memento memento = new Memento("初始狀態(tài)");System.out.println("當(dāng)前狀態(tài): " + memento.getState());memento.setState("修改后的狀態(tài)");System.out.println("修改后的狀態(tài): " + memento.getState());memento.saveToFile("memento.ser");Memento restoredMemento = Memento.restoreFromFile("memento.ser");System.out.println("恢復(fù)后的狀態(tài): " + restoredMemento.getState());}
}
在這個(gè)示例中,我們創(chuàng)建了一個(gè)名為Memento的類,它實(shí)現(xiàn)了Serializable接口。我們?yōu)檫@個(gè)類添加了一個(gè)私有成員變量state,以及一個(gè)構(gòu)造函數(shù)、一個(gè)獲取狀態(tài)的方法、一個(gè)設(shè)置狀態(tài)的方法、一個(gè)保存狀態(tài)到文件的方法和一個(gè)從文件恢復(fù)狀態(tài)的方法。在main方法中,我們創(chuàng)建了一個(gè)Memento對(duì)象,修改了它的狀態(tài),然后將它的狀態(tài)保存到文件中。接著,我們從文件中恢復(fù)了這個(gè)對(duì)象的狀態(tài),并打印出來。