23 Design Patterns Chapter 18: Java Memorandum Pattern
Definition: Capture the internal state of an object without destroying encapsulation and save this state outside the object. This will restore the object to its original saved state.
Type: Behavior class
Class diagram:
When we are programming, we often need to save the intermediate state of the object, and when needed, we can restore it to this state. For example, when we use Eclipse to program, if we make a mistake in writing (for example, accidentally deleted a few lines of code), we want to return the status before deletion, so we can use Ctrl+Z to return. At this time, we can use the memo mode to achieve it.
Structure of memo mode
Initiator: Record the internal status of the current moment, be responsible for defining which states belong to the backup scope, and be responsible for creating and restoring memorandum data.
Memorandum: Responsible for storing the internal state of the initiator object and providing the internal state required by the initiator when needed.
Management Role: Manage memorandums, save and provide memorandums.
General code implementation
class Originator { private String state = ""; public String getState() { return state; } public void setState(String state) { this.state = state; } public Memento createMemento(){ return new Memento(this.state); } public void restoreMemento(Memento memento){ this.setState(memento.getState()); } } class Memento { private String state = ""; public Memento(String state){ this.state = state; } public String getState() { return state; } public void setState(String state) { this.state = state; } } class Caretaker { private Memento memento; public Memento getMemento(){ return memento; } public void setMemento(Memento memento){ this.memento = memento; } } public class Client { public static void main(String[] args){ Originator originator = new Originator(); originator.setState("Status 1"); System.out.println("Initial state:"+originator.getState()); Caretaker caretaker = new Caretaker(); caretaker.setMemento(originator.createMemento()); originator.setState("Status2"); System.out.println("Status after changing:"+originator.getState()); originator.restoreMemento(caretaker.getMemento()); System.out.println("Status after recovery:"+originator.getState()); } } The code demonstrates an example of single state single backup. The logic is very simple: the state variable in the Originator class needs to be backed up so that it can be restored when needed; in the Memento class, there is also a state variable used to store the temporary state of the state variable in the Originator class; and the Caretaker class is used to manage the memorandum class, which is used to write states or retrieve states into the memorandum object.
Multi-state Multi-Backup Memo
In the example of the general code demonstration, the Originator class has only one state variable that needs to be backed up, while usually, the initiator role is usually a javaBean, there are more than one variables that need to be backed up in the object, and more than one state that needs to be backed up. This is a multi-state multi-backup memo.
There are many ways to implement memos. There are many deformations and processing methods for memos. Methods like general code are generally not used. In most cases, memos are multi-state and multiple backups. In fact, it is also very simple to implement multi-state and multi-backup. The most commonly used method is to add a Map container to Memento to store all states, and use a Map container in the Caretaker class to store all backups. Below we give an example of multi-state and multi-backup:
class Originator { private String state1 = ""; private String state2 = ""; private String state3 = ""; public String getState1() { return state1; } public void setState1(String state1) { this.state1 = state1; } public String getState2() { return state2; } public void setState2(String state2) { this.state2 = state2; } public String getState3() { return state3; } public void setState3(String state3) { this.state3 = state3; } public Memento createMemento(){ return new Memento(BeanUtils.backupProp(this)); } public void restoreMemento(Memento memento){ BeanUtils.restoreProp(this, memento.getStateMap()); } public String toString(){ return "state1="+state1+"state2="+state2+"state3="+state3; } } class Memento { private Map<String, Object> stateMap; public Memento(Map<String, Object> map){ this.stateMap = map; } public Map<String, Object> getStateMap() { return stateMap; } public void setStateMap(Map<String, Object> stateMap) { this.stateMap = stateMap; } } class BeanUtils { public static Map<String, Object> backupProp(Object bean){ Map<String, Object> result = new HashMap<String, Object>(); try{ BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor des: descriptors){ String fieldName = des.getName(); Method getter = des.getReadMethod(); Object fieldValue = getter.invoke(bean, new Object[]{}); if(!fieldName.equalsIgnoreCase("class")){ result.put(fieldName, fieldValue); } } } } catch(Exception e){ e.printStackTrace(); } return result; } public static void restoreProp(Object bean, Map<String, Object> propMap){ try { BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor des: descriptors){ String fieldName = des.getName(); if(propMap.containsKey(fieldName)){ Method setter = des.getWriteMethod(); setter.invoke(bean, new Object[]{propMap.get(fieldName)}); } } } catch (Exception e) { e.printStackTrace(); } } } class Caretaker { private Map<String, Memento> memMap = new HashMap<String, Memento>(); public Memento getMemento(String index){ return memMap.get(index); } public void setMemento(String index, Memento memento){ this.memMap.put(index, memento); } } class Client { public static void main(String[] args){ Originator ori = new Originator(); Caretaker caretaker = new Caretaker(); ori.setState1("China"); ori.setState2("Strong"); ori.setState3("Prosperity"); System.out.println("===Initialization status===/n"+ori); caretaker.setMemento("001",ori.createMemento()); ori.setState1("Software"); ori.setState2("Structure"); ori.setState3("Excellent"); System.out.println("===Modified status===/n"+ori); ori.restoreMemento(caretaker.getMemento("001")); System.out.println("===Restored status===/n"+ori); } } Advantages and disadvantages of memorandum mode and applicable scenarios
The advantages of the memo mode are:
When the status in the initiator role changes, it may be a wrong change. We can restore this wrong change using the memo mode.
The status of the backup is saved outside the initiator role, so the initiator role does not need to manage the status of each backup.
The disadvantages of the memo mode are:
In actual applications, the memorandum mode is multi-state and multi-backup. The state of the initiator role needs to be stored in the memorandum object, which consumes resources relatively severely.
If you need to provide rollback operations, using memo mode is very suitable, such as jdbc transaction operations, Ctrl+Z recovery of text editors, etc.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.