1. Introduction
Everyone makes mistakes and hopes to have a "regret medicine" to make up for their mistakes and start over, but the reality is cruel. In computer applications, customers also often make mistakes. Can we provide them with "regret medicine"? Of course, it is possible and necessary. This function is realized by "memo mode".
In fact, many application software provide this function, such as Word, Notepad, Photoshop, Eclipse and other software. When you press Ctrl+Z during editing, you can undo the current operation and restore the document to its previous state; In addition, the back button in IE, rollback operation in database transaction management, intermediate result archiving function when playing games, backup operation of database and operating system, repentance function in chess games, etc. all belong to this category.
Memo mode can record the internal state of an object. When the user regrets, it can undo the current operation and restore the data to its original state.
2. Definitions
Definition of memo mode: capture the internal state of an object without destroying the encapsulation, and save the state outside the exclusive so that the object can be restored to the original saved state when necessary in the future. This mode is also called snapshot mode.
3. Advantages
- Provides a mechanism to restore state. When users need it, they can easily restore the data to a historical state.
- The encapsulation of internal state is realized. Except for the initiator who created it, no other object can access this state information.
- Simplified the human. The initiator does not need to manage and save each backup of internal status during the period. All status information is saved in the memo and managed by the manager, which is in line with the principle of single responsibility.
4. Disadvantages
Large resource consumption. If the internal state information to be saved is too much or cumbersome, it will occupy a large memory resource.
5. Structure
The core of memo mode is to design memo classes and manager classes for managing memos.
Its main roles are as follows:
- Originator role: records the internal status information at the current time, provides the function of creating memos and recovering memo data, and realizes other business functions. It can access all the information in memos.
- Memo role: responsible for storing the internal status of the initiator and providing these internal status to the initiator when necessary.
- Manager role: manages memos and provides the function of saving and obtaining memos, but it cannot access and modify the contents of memos.
Its structure diagram is as follows:
6. Application scenarios
- Scenes that need to save and restore data, such as the archiving function of intermediate results when playing games.
- You need to provide a scenario that can roll back operations, such as Word, Notepad, Photoshop, Eclipse and other software, pressing Ctrl+Z during compilation, and transaction operations in the database.
7. Code example
1. Simple example
/** * memorandum */ class Memento{ @Getter @Setter private String state; public Memento(String state){ this.state = state; } } /** * Initiator */ class Originator{ @Getter @Setter private String state; public Memento createMemento(){ return new Memento(state); } public void restoreMemento(Memento memento){ this.setState(memento.getState()); } } /** * controller */ class Caretaker{ @Getter @Setter private Memento memento; } public class MementoSimpleTest { public static void main(String[] args){ Originator originator = new Originator(); Caretaker caretaker = new Caretaker(); originator.setState("S0"); System.out.println("Initial state:" + originator.getState()); caretaker.setMemento(originator.createMemento()); originator.setState("S1"); System.out.println("New status:" + originator.getState()); originator.restoreMemento(caretaker.getMemento()); System.out.println("Recovery status:" + originator.getState()); } }
2. Application examples
Example: design a blind date game using memo mode.
Analysis: if there are four beauties, Xi Shi, Wang Zhaojun, Diao Chan and Yang Yuhuan, you can choose one of them as your lover; Of course, if you are not satisfied with the previous choice, you can choose again, but I hope you don't spend too much time; This game provides regret function. It is more appropriate to use "memo mode" design.
First, a Girl class is designed. It is a memo role, which provides the function of obtaining and storing beauty information; Then, a blind date (You) class is designed, which is the initiator role. It records the internal status information (the name of the temporary wife) at the current time, and provides the functions of creating memos and recovering memo data; Finally, define a GirlStack class, which is a manager role, responsible for managing memos, and is used to save the beauty information previously selected by a blind date (You), but it can only save 4 at most, providing regret function.
The client class is designed as a form program, which includes a GirlStack object and a blind date (You) object. It implements the event processing method actionPerformed (ActionEvent e) of the ActionListener interface, and displays the four beauty images and the beauty images selected by the blind date (You) in the form.
The structure diagram is as follows:
Code example:
/** * Memo: Beauty */ class Girl{ @Getter @Setter private String name; public Girl(String name){ this.name = name; } } /** * Sponsor: you */ class You{ @Getter @Setter private String wifeName; public Girl createMemento(){ return new Girl(wifeName); } public void restoreMemento(Girl p){ setWifeName(p.getName()); } } /** * Manager: Beauty stack */ class GirlStack{ private Girl[] girls; private int top; GirlStack(){ girls = new Girl[5]; top = -1; } public boolean push(Girl p){ if(top >= 4){ System.out.println("You're too playful. You change around!"); return false; }else{ girls[++top] = p; return true; } } public Girl pop(){ if(top <= 0){ System.out.println("The beauty stack is empty!"); return girls[0]; }else{ return girls[top--]; } } } /** * Customer form class */ class DatingGameWin extends JFrame implements ActionListener{ JPanel centerJP, eastJP; JRadioButton girl1, girl2, girl3, girl4; JButton button1, button2; String fileName; JLabel g; You you; GirlStack girls; DatingGameWin(){ super("Using memo mode to design blind date game"); you = new You(); girls = new GirlStack(); this.setBounds(0, 0, 900, 300); this.setResizable(false); fileName = "src/memento/photo/Four beauties.jpg"; g = new JLabel(new ImageIcon(fileName), JLabel.CENTER); centerJP = new JPanel(); centerJP.setLayout(new GridLayout(1, 4)); centerJP.setBorder(BorderFactory.createTitledBorder("The four beauties are as follows:")); centerJP.add(g); this.add("Center", centerJP); eastJP = new JPanel(); eastJP.setLayout(new GridLayout(1, 1)); eastJP.setBorder(BorderFactory.createTitledBorder("Your chosen lover is:")); this.add("East", eastJP); JPanel southJP = new JPanel(); JLabel info = new JLabel("The four beauties have "the appearance of sinking fish and falling geese, and the appearance of closing the moon and ashamed of flowers". Who do you choose?"); girl1 = new JRadioButton("Xi Shi", true); girl2 = new JRadioButton("army officer's hat ornaments"); girl3 = new JRadioButton("Wang Zhaojun"); girl4 = new JRadioButton("Yang Yuhuan"); button1 = new JButton("determine"); button2 = new JButton("return"); ButtonGroup group = new ButtonGroup(); group.add(girl1); group.add(girl2); group.add(girl3); group.add(girl4); southJP.add(info); southJP.add(girl1); southJP.add(girl2); southJP.add(girl3); southJP.add(girl4); southJP.add(button1); southJP.add(button2); button1.addActionListener(this); button2.addActionListener(this); this.add("South", southJP); showPicture("blank"); you.setWifeName("blank"); girls.push(you.createMemento()); } void showPicture(String name){ eastJP.removeAll(); eastJP.repaint(); you.setWifeName(name); fileName = "src/memento/photo/" + name + ".jpg"; g = new JLabel(new ImageIcon(fileName), JLabel.CENTER); eastJP.add(g); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } @Override public void actionPerformed(ActionEvent e) { boolean ok = false; if(e.getSource() == button1){ ok = girls.push(you.createMemento()); if(ok && girl1.isSelected()){ showPicture("Xi Shi"); }else if(ok && girl2.isSelected()){ showPicture("army officer's hat ornaments"); }else if(ok && girl3.isSelected()){ showPicture("Wang Zhaojun"); }else if(ok && girl4.isSelected()){ showPicture("Yang Yuhuan"); } }else if(e.getSource() == button2){ you.restoreMemento(girls.pop()); showPicture(you.getWifeName()); } } } public class DatingGameTest { public static void main(String[] args){ new DatingGameWin(); } }
Rendering:
3. Extension of memo mode
In the memo mode above, there are examples of single state backup and multi state backup. The following describes how memo mode is mixed with prototype mode. In the memo mode, the information of the "initiator" is backed up by defining the "Memo", and the clone() method of the prototype mode has the self backup function. Therefore, if the initiator implements the clonable interface, it has the function of backing up itself. At this time, the memo class can be deleted.
The structure diagram is as follows:
/** * Initiator prototype */ class OriginatorPrototype implements Cloneable{ @Getter @Setter private String state; public OriginatorPrototype createMemento(){ return this.clone(); } public void restoreMemento(OriginatorPrototype opt){ this.setState(opt.getState()); } public OriginatorPrototype clone(){ try { return (OriginatorPrototype) super.clone(); }catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } } /** * Prototype Manager */ class PrototypeCaretaker{ private OriginatorPrototype opt; public void setMemento(OriginatorPrototype opt){ this.opt = opt; } public OriginatorPrototype getMemento(){ return opt; } } public class MementoAndPrototypeTest { public static void main(String[] args){ OriginatorPrototype or = new OriginatorPrototype(); PrototypeCaretaker cr = new PrototypeCaretaker(); or.setState("S0"); System.out.println("Initial state:" + or.getState()); cr.setMemento(or.createMemento()); or.setState("S1"); System.out.println("New status:" + or.getState()); or.restoreMemento(cr.getMemento()); System.out.println("Recovery status:" + or.getState()); } }
4. Use memo mode to realize the draft box function
You are sure to use a rich text editor when publishing articles on the Internet. The editor usually comes with operations such as draft box and undo.
Next, we use memo mode to implement such a function. Suppose that when we publish an article, the process of editing the article takes a long time, and it will not be revoked and modified continuously. It may even take several days to write a high-quality article, so the edited content may be saved to the draft box in real time.
The code example is as follows:
/** * Text editor class: initiator role class */ @Getter @Setter @ToString @AllArgsConstructor class TestEditor{ private String title; private String content; private String images; public ArticleMemento saveToMemento(){ ArticleMemento articleMemento = new ArticleMemento(title, content, images); return articleMemento; } public void undoFromMemento(ArticleMemento articleMemento){ this.title = articleMemento.getTitle(); this.content = articleMemento.getContent(); this.images = articleMemento.getImages(); } } /** * Memo role class */ @Getter @Setter @ToString @AllArgsConstructor class ArticleMemento{ private String title; private String content; private String images; } /** * Memo management role draft box class */ class Drafts{ private final Stack<ArticleMemento> STACK = new Stack<>(); public ArticleMemento getMemento(){ ArticleMemento articleMemento = STACK.pop(); return articleMemento; } public void addMemento(ArticleMemento memento){ STACK.push(memento); } } public class MementoTextEditorTest { public static void main(String[] args){ Drafts drafts = new Drafts(); TestEditor editor = new TestEditor("Java Design pattern", "Memo mode", "1.jpg"); ArticleMemento memento = editor.saveToMemento(); drafts.addMemento(memento); System.out.println("title:" + editor.getTitle()); System.out.println("Content:" + editor.getContent()); System.out.println("Illustration:" + editor.getImages()); System.out.println("Temporary storage succeeded!"); System.out.println("Complete information:" + editor); System.out.println(); System.out.println("=========Modify the article for the first time=========="); editor.setTitle("Java Design mode (supplementary description)"); editor.setTitle("Memo mode (supplementary description)"); System.out.println("Complete information:" + editor); System.out.println("=========First modification completed=========="); System.out.println(); memento = editor.saveToMemento(); drafts.addMemento(memento); System.out.println("========Saved draft box=========="); System.out.println(); System.out.println("=========Modify the article again=========="); editor.setTitle("Java Design mode (supplemented again)"); editor.setContent("Memo mode (to be added again)"); System.out.println("Complete information:" + editor); System.out.println("=========Modification completed again=========="); System.out.println(); System.out.println("=========Start of first revocation=========="); memento = drafts.getMemento(); editor.undoFromMemento(memento); System.out.println("Complete information:" + editor); System.out.println("=========First revocation complete=========="); System.out.println(); System.out.println("=========Undo start again=========="); memento = drafts.getMemento(); editor.undoFromMemento(memento); System.out.println("Complete information:" + editor); System.out.println("=========Undo again complete=========="); } }
The Stack class defined in the draft box is a subclass of Vector, which implements a standard last in first out Stack.
The main methods are as follows:
Method definition | Method description |
---|---|
boolean empty() | Determine whether the stack is empty |
Object peek() | View the object at the top of the stack, but do not remove it from the stack |
Object pop() | Removes the object at the top of the stack and returns it as the value of this function |
Object push(Object element) | Push the object to the top of the stack |
int search(Object element) | Returns the position of the object in the stack, based on 1 |