In this note I will describe the pattern “Snapshot” or “Memento”
This pattern refers to “Behavioural” design patterns.
Let’s say we are developing a graphical editor, and we need to add the ability to roll back actions on user command. It is also very important that the system components do not have access to the internal state of the rolled back “actions”, when implementing this pattern, other system components have access only to the snapshot object without the ability to change its internal state, with the provision of a clear, simple external interface. To solve this problem, the “Snapshot” or “Keeper” pattern is used.
An example of the operation of the “Snapshot” is presented below:
When clicked, the sprite appears, when clicked on the twisted arrow, the action is canceled – the sprite disappears. The example consists of three classes:
- Canvas on which sprites and graphical interface are displayed.
- Screen controller, it handles clicks and manages the logic of the screen.
- Canvas states that are saved on every change are rolled back when needed by the screen controller.
In the context of the pattern “Snapshot”, the classes are:
- Canvas is the source, the states of this class are saved as snapshots, for subsequent rollback on request. Also, the source must be able to restore the state when a snapshot is passed to it.
- Controller – the keeper, this class knows how and when to save/roll back states.
- State is a snapshot, a class that stores the state of the source, plus date information or an index that can be used to accurately determine the order of rollback.
An important feature of the pattern is that only the source should have access to the internal fields of the saved state in the snapshot, this is necessary to protect snapshots from changes from the outside (from handy developers who want to change something bypassing encapsulation, breaking the logic of the system). To implement encapsulation, embedded classes are used, and in C++, the ability to specify friend classes is used. Personally, I implemented a simple version without encapsulation for Rise, and using Generic when implementing for Swift. In my version, – Memento gives its internal state only to entities of the same class as the state:
Sources
https://refactoring.guru/design-patterns/memento
Source code
https://gitlab.com/demensdeum/patterns/< /p>