In Dr. Yan Hong’s JAVA and Pattern, the Memento Pattern is described as follows at the beginning: The Memento Pattern, also called Snapshot Pattern or Token Pattern, is the behavior Pattern of objects. A memo object is an object that stores a snapshot of the internal state of another object. The purpose of the memo pattern is to Capture, externalize, and store an object’s state without breaking encapsulation, so that the object can be restored to its stored state at a later time. The memo pattern is often used with the command pattern and the iteration subpattern.

The main purpose of the memo pattern is to capture the internal state of an object without breaking encapsulation and store the state outside of the object so that the object can be restored to its original saved state at the appropriate time. Combined, there are three meanings:

  1. Does not break encapsulation: the object only releases the interface that should be exposed, and cannot expose the interface that should not be released.
  2. Capture and externalize the internal state of an object: Save the state of an object and store it externally for recovery;
  3. The internal state of the object is stored in the external manager class through the memo object.

The core roles of memo mode include Memento, Originator, and Caretaker.

Memo Role The memo role is used to store the internal state of the sponsor object, but it is up to the sponsor role to determine which field values to store. The internal data of the memo object can only be accessed by the initiator object. Other objects should not access the internal data of the memo object. In summary, the responsibilities of the memo role are as follows:

  1. The internal state of the initiator role is stored and stored externally.
  2. Memos protect their contents from being read by any object other than the Originator object, so the memo object is typically implemented as an internal class of the Originator object and as private, and then usually a narrow interface identifies the type of the object for external interaction.

Initiator role The initiator role is also called the originator. The initiator role stores its state at a time through the memo object and can also use the state saved by the memo to restore it. The initiator role serves two purposes:

  1. Provide a method to capture a moment, create a memo object in the method, save the need to save the state, and then throw the memo object management;
  2. Provides a method for state recovery through the memo object;

Responsible Role Responsible for managing memo objects. Here we need to be clear about the following points:

  1. A responsible object is not necessarily required in the memo pattern. Broadly speaking, after calling the initiator role to get the memo object, where the memo is placed, that object is the manager object.
  2. Rather than managing just one memo object, the master object can manage multiple memo objects.
  3. The person in charge in the narrow sense only manages the same kind of memo objects, but the manager in the broad sense can manage different types of memo objects.
  4. The principal object needs to realize the basic function is: store the memo object and get the memo object. In terms of function, it is a caching function or a simple object instance pool.
  5. Although the responsible role can access the memo object, it cannot access the internal data of the memo object.

In layman’s terms, a memo is a generic class that holds the state associated with the sponsor role, which is then handed over to the lead role for management with save and restore functionality.

Case presentation

Take world of Warcraft as an example. When just learning to play world of warcraft, first learning man-machine war, play to is rising, roommate suddenly call you to have a meal, that can only save the progress first, close the computer to cool down, eat a meal to come back directly open just save the progress, read after completion then play. In this case, it’s a memo pattern.

Create the initiator role/originator role

public class Dota {
	/** * game start time */
	private int time;
	/** ** Number of players */
	private int killPeople;
	/** * Whether to suspend */
	private boolean isPause = false;
	
	/** * play the game */
	public void playGame(a){
		new Thread(new Runnable() {
			
			@Override
			public void run(a) {
				while(! isPause){ System.out.println("The game is on:" + time + "Minutes, head count:" + killPeople);
					time++;
					killPeople++;
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
	
	/** * end the game */
	public void exitGame(a){
		isPause = true;
		System.out.println("===== End the game =====");
		System.out.println("The game is on:" + time + "Minutes, head count:" + killPeople);
		System.out.println("= = = = = = = = = = = = = = =");
	}
	
	/** * Save to get the current game info *@return* /
	public GameInfo saveGameInfo(a){
		return new GameInfo(time, killPeople);
	}
	
	/** * Reload the game *@param gameInfo
	 */
	public void loadGame(GameInfo gameInfo){
		time = gameInfo.getTime();
		killPeople = gameInfo.getKillPeople();
		System.out.println("===== Resume game =====");
		System.out.println("The game is on:" + time + "Minutes, head count:" + killPeople);
		System.out.println("= = = = = = = = = = = = = = =");
		isPause = false; }}Copy the code

In the originator definition, a method is defined to get the internal state and store it in a memo object. A loadGame method is also defined to read the contents of the memo.

Definition memorandum

/** * The memo role, a special class used to store information from the originator *@author Iflytek_dsw
 *
 */
public class GameInfo {
	private int time;
	private int killPeople;
	public GameInfo(int time, int killPeople) {
		super(a);this.time = time;
		this.killPeople = killPeople;
	}
	public int getTime(a) {
		return time;
	}
	public void setTime(int time) {
		this.time = time;
	}
	public int getKillPeople(a) {
		return killPeople;
	}
	public void setKillPeople(int killPeople) {
		this.killPeople = killPeople; }}Copy the code

As you can see, the memo is a simple entity class that holds the state of the originator. The contents of this class can only be accessed by the originator, that is, a wide interface is established between the originator and the memo object. The originator can see a wide interface that allows it to access all the data it needs to return to the previous state. Typically implemented as a private inner class within the originator.

Define responsible/manager roles

/** * The manager role, as the memo mode management role *@author Iflytek_dsw
 *
 */
public class GameManager {
	private Map<String, GameInfo> gameMap;
	private static GameManager instance;
	private GameManager(a){
		gameMap = new ConcurrentHashMap<>();
	}
	
	public static GameManager getGameManager(a){
		if(instance == null) {synchronized(GameManager.class){
				if(instance == null){
					instance = newGameManager(); }}}return instance;
	}
	
	/** * Save game info *@param name
	 * @param gameInfo
	 */
	public void saveGameInfo(String name, GameInfo gameInfo){
		gameMap.put(name, gameInfo);
	}
	
	/** * Read game info *@param name
	 * @return* /
	public GameInfo getGameInfo(String name){
		returngameMap.get(name); }}Copy the code

The director role is used to manage the memo object. The manager object does not manage only one memo object, but can manage multiple memo objects. Managers see only a narrow interface to the memo, which is usually implemented without any method, just a type identifier. Narrow interfaces allow managers to pass memos only to other objects

The client

public class Client {

	/ * * *@param args
	 */
	public static void main(String[] args) {
		Dota dota = new Dota();
		dota.playGame();
		try {
			// Play for a while
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// Pause the game
		dota.exitGame();
		GameManager.getGameManager().saveGameInfo("Memo Mode", dota.saveGameInfo());
		
		// Resume the game
		dota.loadGame(GameManager.getGameManager().getGameInfo("Memo Mode")); }}Copy the code

The results

The game is on:0Minutes, head count:0The game is on:1Minutes, head count:1The game is on:2Minutes, head count:2The game is on:3Minutes, head count:3The game is on:4Minutes, head count:4The game is on:5Minutes, head count:5The game is on:6Minutes, head count:6The game is on:7Minutes, head count:7The game is on:8Minutes, head count:8The game is on:9Minutes, head count:9The game is on:10Minutes, head count:10The game is on:11Minutes, head count:11The game is on:12Minutes, head count:12The game is on:13Minutes, head count:13The game is on:14Minutes, head count:14The game is on:15Minutes, head count:15The game is on:16Minutes, head count:16The game is on:17Minutes, head count:17The game is on:18Minutes, head count:18The game is on:19Minutes, head count:19===== end the game ===== the game begins:20Minutes, head count:20=============== ===== Resume game ===== game started:20Minutes, head count:20=============== Game on:20Minutes, head count:20The game is on:21Minutes, head count:21The game is on:22Minutes, head count:22The game is on:23Minutes, head count:23
Copy the code

Pros and cons of the memo model

advantages

  1. Better encapsulation, through the use of memo object to encapsulate the primary object’s internal state, while the object is stored in the primary object of external, but due to the narrow interface to a memorandum does not provide any method, because effectively guarantee the internal state of primary packaging, not the primary internal implementation details of the exposed to the external device object.
  2. Simplifying the originator, the memo object is kept outside of the originator object, allowing customers to manage the state of their requests, simplifying the originator object.

disadvantages

Creating memo objects frequently can lead to significant overhead

Related patterns

(1) Memo mode and command mode

Command mode implementation, in order to achieve the command undo and redo, you can use the memo mode, in the command operation record the state before and after the operation, and then in the command undo and redo, directly use the corresponding memo object to restore the state.

(2) Memo mode and prototype mode

When creating a memo object, if all or most of the state in the primary object needs to be saved, a neat way is to simply clone a primary object. In other words, the memo object holds an instance of the original object.