1. Overview
Memo mode provides an implementation mechanism for state recovery that allows users to easily go back to a specific historical step. When a new state is invalid or has a problem, a temporary stored memo can be used to restore the state, and many software offers Undo.Operations such as Word, Notepad, Photoshop, IDEA, etc. can undo the current operation when you press the Ctrl+Z key combination while editing, restoring the document to its previous state; and in the browserBack-up keys, rollback operations in database transaction management, archiving of intermediate results while playing games, backup operations of databases and operating systems, and repentance functions in chess games all belong to this category.
Definition: Also known as snapshot mode, captures the internal state of an object without destroying its encapsulation and saves it outside of it so that it can be restored to its original saved state later when needed.
2. Structure
The main roles of the memo mode are as follows:
Originator role: records internal status information at the current moment, provides the ability to create and restore memo data, and implements other business functions that access all information in the memo.
Memento role: responsible for storing the internal status of the sponsors and providing them to the sponsors when needed.
Caretaker role: Manage memos and provide the ability to save and retrieve them, but they cannot access and modify the contents of the memo.
The memo has two equivalent interfaces:
Narrow interface: A manager (any object other than the other initiator object) sees a narror interface for a memo, which only allows him to pass the memo object to other objects.
Wide Interface: Contrary to the narrow interface seen by the administrator, the initiator object can see a wide interface that allows it to read all the data to restore the internal state of the initiator object.
3. Case Realization
Game Challenge BOSS: A scene in the game, where a character has life, attack, defense and other data, will not be the same before and after playing Boss. We allow players to restore the game to its pre-duel state if they feel the duel is not working well with Boss.
There are two ways to achieve the above cases: White Box memo mode and Black Box memo mode.
3.1. White Box memo mode
The memo role provides an interface to any object, that is, a wide interface, and the internal stored state of the memo role is exposed to all objects. The class diagram is as follows:
The code is as follows:
//Game Role Class public class GameRole { private int vit; //vitality private int atk; //Aggressivity private int def; //Defense //Initialization state public void initState() { this.vit = 100; this.atk = 100; this.def = 100; } //Battle public void fight() { this.vit = 0; this.atk = 0; this.def = 0; } //Save Role State public RoleStateMemento saveState() { return new RoleStateMemento(vit, atk, def); } //Reply to Role Status public void recoverState(RoleStateMemento roleStateMemento) { this.vit = roleStateMemento.getVit(); this.atk = roleStateMemento.getAtk(); this.def = roleStateMemento.getDef(); } public void stateDisplay() { System.out.println("Role Vitality:" + vit); System.out.println("Role Attack:" + atk); System.out.println("Role Defense:" + def); } public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } } //Game State Storage Class (Memo Class) public class RoleStateMemento { private int vit; private int atk; private int def; public RoleStateMemento(int vit, int atk, int def) { this.vit = vit; this.atk = atk; this.def = def; } public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } } //Role Status Manager Class public class RoleStateCaretaker { private RoleStateMemento roleStateMemento; public RoleStateMemento getRoleStateMemento() { return roleStateMemento; } public void setRoleStateMemento(RoleStateMemento roleStateMemento) { this.roleStateMemento = roleStateMemento; } } //Test Class public class Client { public static void main(String[] args) { System.out.println("------------War Boss Front------------"); //Before World War Boss GameRole gameRole = new GameRole(); gameRole.initState(); gameRole.stateDisplay(); //Save Progress RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); roleStateCaretaker.setRoleStateMemento(gameRole.saveState()); System.out.println("------------War Boss after------------"); //Great wastage during the war against Boss gameRole.fight(); gameRole.stateDisplay(); System.out.println("------------Pre-recovery status------------"); //Pre-recovery status gameRole.recoverState(roleStateCaretaker.getRoleStateMemento()); gameRole.stateDisplay(); } }
The Whitebox memo mode is destructive of encapsulation. But programmer self-discipline also enables most of the intent of the mode to be achieved to some extent.
3.2 Black Box Memo Mode
The memo role provides a wide interface to the originator object and a narrow interface to other objects. In Java, the way to achieve a dual interface is to design the memo class as an internal member class of the originator human.
Setting RoleStateMemento as the internal class of GameRole encapsulates the RoleStateMemento object inside the GameRole and provides an identifying interface Memento outside for use by RoleStateCaretaker and other objects. This way the GameRole class sees all the interfaces of RoleStateMemento and RoleStateCaretakerOther objects see only interfaces exposed by the identity interface Memento, thus maintaining the encapsulated type. The class diagram is as follows:
The code is as follows:
Narrow interface Memento, which is an identity interface, so no method is defined
public interface Memento { }
Defines the initiator human GameRole and internally defines the memo internal class RoleStateMemento, which is set to private.
/Game Role Class public class GameRole { private int vit; //vitality private int atk; //Aggressivity private int def; //Defense //Initialization state public void initState() { this.vit = 100; this.atk = 100; this.def = 100; } //Battle public void fight() { this.vit = 0; this.atk = 0; this.def = 0; } //Save Role State public Memento saveState() { return new RoleStateMemento(vit, atk, def); } //Reply to Role Status public void recoverState(Memento memento) { RoleStateMemento roleStateMemento = (RoleStateMemento) memento; this.vit = roleStateMemento.getVit(); this.atk = roleStateMemento.getAtk(); this.def = roleStateMemento.getDef(); } public void stateDisplay() { System.out.println("Role Vitality:" + vit); System.out.println("Role Attack:" + atk); System.out.println("Role Defense:" + def); } public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } private class RoleStateMemento implements Memento { private int vit; private int atk; private int def; public RoleStateMemento(int vit, int atk, int def) { this.vit = vit; this.atk = atk; this.def = def; } public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } } }
The memo object available to the responsible role class RoleStateCaretaker is a Memento interface. Since this interface is only an identification interface, it is not possible for the responsible role to change the contents of this memo object.
//Role Status Manager Class public class RoleStateCaretaker { private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } }
Client Test Class
public class Client { public static void main(String[] args) { System.out.println("------------War Boss Front------------"); //Before World War Boss GameRole gameRole = new GameRole(); gameRole.initState(); gameRole.stateDisplay(); //Save Progress RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); roleStateCaretaker.setMemento(gameRole.saveState()); System.out.println("------------War Boss after------------"); //Great wastage during the war against Boss gameRole.fight(); gameRole.stateDisplay(); System.out.println("------------Pre-recovery status------------"); //Pre-recovery status gameRole.recoverState(roleStateCaretaker.getMemento()); gameRole.stateDisplay(); } }
4. Advantages and disadvantages
Strengths:
Provides a mechanism to restore state. It is easier to restore data to a historical state when the user needs it.
Implements encapsulation of internal states. These state information is inaccessible to any object except the initiator who created it.
Sponsors are simplified. Sponsors do not need to manage and maintain individual backups of their internal status. All status information is saved in a memo and managed by a manager, which is consistent with the single responsibility principle.
Disadvantages:
High resource consumption. Large memory resources will be consumed if too much or especially frequent internal state information is to be saved.
5. Use scenarios
Scenes where data needs to be saved and restored, such as the ability to archive intermediate results while playing a game.
You need to provide a scene where you can roll back operations, such as Word, Notepad, Photoshop, idea, and other software that press Ctrl+Z when editing, as well as transaction operations in the database.