This is the 12th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
An overview of the
The memo mode provides an implementation mechanism for state recovery, enabling users to easily go back to a specific historical step. When the new state is invalid or has problems, users can use the temporarily stored memo to restore the state. Many software provide Undo operations. Such as Word, Notepad, Photoshop, IDEA and other software can undo the current operation when pressing Ctrl+Z during editing, so that the document can be restored to the previous state; There are back key in the browser, database transaction management in the rollback operation, playing the game when the intermediate results of the archiving function, database and operating system backup operation, chess games in the function of regret are all in this category.
Definition:
Also called snapshot mode, without breaking encapsulation, captures the internal state of an object and stores the state outside of the object so that the object can be restored to its original state when needed.
structure
The main roles of the memo mode are as follows:
- Originator: Records internal status information of the current moment, creates memos, restores memo data, and implements other service functions. It can access all information in memos.
- Memento role: Responsible for storing the internal state of the initiator and providing this internal state to the initiator when needed.
- Caretaker role: Caretaker manages the memo, saves and obtains the memo, but cannot access or modify the memo.
The memo has two equivalent interfaces:
- Narrow Interface: the Caretaker object (and any other object other than the initiator object) sees the memo’s narror Interface, which only allows the Caretaker to pass the memo object to other objects.
- Wide Interface: In contrast to the narrow Interface the manager sees, the initiator object sees a wide Interface that allows it to read all data to restore the internal state of the initiator object.
Case implementation
【 example 】 The game challenges the BOSS
A certain scene in the game, a game character has vitality, attack, defense and other data, before and after the Boss fight will be different, we allow players to feel the effect of the Boss duel is not ideal can be restored to the game before the duel state.
To implement the above case, there are two ways:
- “White box” memo mode
- “Black box” memo mode
“White box” memo mode
The memo role provides an interface, or broad interface, to any object, and the state stored inside the memo role is exposed to all objects. The class diagram is as follows:
The code is as follows:
// Game character class
public class GameRole {
private int vit; / / life
private int atk; / / damage
private int def; / / defense force
// Initialization state
public void initState(a) {
this.vit = 100;
this.atk = 100;
this.def = 100;
}
/ / combat
public void fight(a) {
this.vit = 0;
this.atk = 0;
this.def = 0;
}
// Save the role status
public RoleStateMemento saveState(a) {
return new RoleStateMemento(vit, atk, def);
}
// Restore role status
public void recoverState(RoleStateMemento roleStateMemento) {
this.vit = roleStateMemento.getVit();
this.atk = roleStateMemento.getAtk();
this.def = roleStateMemento.getDef();
}
public void stateDisplay(a) {
System.out.println("Character Vitality:" + vit);
System.out.println("Character damage:" + atk);
System.out.println("Character defense:" + def);
}
public int getVit(a) {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getAtk(a) {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef(a) {
return def;
}
public void setDef(int def) {
this.def = def; }}// Game state storage (memos)
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(a) {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getAtk(a) {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef(a) {
return def;
}
public void setDef(int def) {
this.def = def; }}// Role state manager class
public class RoleStateCaretaker {
private RoleStateMemento roleStateMemento;
public RoleStateMemento getRoleStateMemento(a) {
return roleStateMemento;
}
public void setRoleStateMemento(RoleStateMemento roleStateMemento) {
this.roleStateMemento = roleStateMemento; }}/ / test class
public class Client {
public static void main(String[] args) {
System.out.println("------------ before Boss ------------");
// Before the Boss fight
GameRole gameRole = new GameRole();
gameRole.initState();
gameRole.stateDisplay();
// Save the progress
RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
roleStateCaretaker.setRoleStateMemento(gameRole.saveState());
System.out.println("------------ after Boss ------------");
// There is a lot of wastage in Boss battles
gameRole.fight();
gameRole.stateDisplay();
System.out.println("------------ restore to previous state ------------");
// Restore the previous stategameRole.recoverState(roleStateCaretaker.getRoleStateMemento()); gameRole.stateDisplay(); }}Copy the code
Analysis: White box memo mode breaks encapsulation. But much of the intent of the pattern can also be achieved to some extent through programmer discipline.
“Black box” memo mode
The memo role provides a wide interface to the initiator object and a narrow interface to other objects. In the Java language, the way to achieve dual interfaces is to design the memo class as an internal member class that initiates humans.
Make RoleStateMemento an internal class of GameRole, thus encapsulating the RoleStatemento object inside GameRole; Provide an external identification interface Memento for RoleStateCaretaker and other objects. Thus the GameRole class sees all the interfaces of RoleStateMemento, while RoleStateCaretaker and other objects see only the interfaces exposed by Memento, which identifies the interface, maintaining the encapsulation. The class diagram is as follows:
The code is as follows:
The narrow interface Memento, which is an identity interface, does not define any methods
public interface Memento {}Copy the code
Define the initiating human GameRole and internally define the memo inner class RoleStateMemento (which is set to private)
/ Game character classpublic class GameRole {
private int vit; / / life
private int atk; / / damage
private int def; / / defense force
// Initialization state
public void initState(a) {
this.vit = 100;
this.atk = 100;
this.def = 100;
}
/ / combat
public void fight(a) {
this.vit = 0;
this.atk = 0;
this.def = 0;
}
// Save the role status
public Memento saveState(a) {
return new RoleStateMemento(vit, atk, def);
}
// Restore 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(a) {
System.out.println("Character Vitality:" + vit);
System.out.println("Character damage:" + atk);
System.out.println("Character defense:" + def);
}
public int getVit(a) {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getAtk(a) {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef(a) {
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(a) {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getAtk(a) {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef(a) {
return def;
}
public void setDef(int def) {
this.def = def; }}}Copy the code
The RoleStateCaretaker class can get a memo object that interfaces to Memento. Since the interface is only an identity interface, the director cannot change the contents of the memo object
// Role state manager class
public class RoleStateCaretaker {
private Memento memento;
public Memento getMemento(a) {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento; }}Copy the code
Client test classes
public class Client {
public static void main(String[] args) {
System.out.println("------------ before Boss ------------");
// Before the Boss fight
GameRole gameRole = new GameRole();
gameRole.initState();
gameRole.stateDisplay();
// Save the progress
RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
roleStateCaretaker.setMemento(gameRole.saveState());
System.out.println("------------ after Boss ------------");
// There is a lot of wastage in Boss battles
gameRole.fight();
gameRole.stateDisplay();
System.out.println("------------ restore to previous state ------------");
// Restore the previous stategameRole.recoverState(roleStateCaretaker.getMemento()); gameRole.stateDisplay(); }}Copy the code
The advantages and disadvantages
1. Advantages:
- Provides a mechanism by which states can be restored. Data can be easily restored to a historical state when the user needs it.
- Internal state encapsulation is realized. No object other than the originator that created it has access to this state information.
- Simplified initiation for humans. The sponsor does not need to manage and keep individual copies of its internal state, all state information is kept in memos and managed by the manager, in line with the principle of single responsibility.
2. Disadvantages:
- High resource consumption. If the internal state information to be saved is too much or too frequent, it will occupy a large amount of memory resources.
Usage scenarios
-
Scenarios where data needs to be saved and recovered, such as archiving of intermediate results while playing a game.
-
Need to provide a scenario of rollback operations, such as Word, Notepad, Photoshop, IDEA and other software during editing Ctrl+Z combination key, as well as transaction operations in the database.