* Grammatical fixes to command pattern * Update bridge pattern readme * Fixes to builder pattern grammar * Update chain of responsibility * Improvements to the composite example * Fixes to headings * Minor updates to decorator pattern * Update facade * Update factory example * Update factory method * Update flyweight * Interpreter explanation * Update iterator readme * Add explanation for mediator pattern * Grammatical fixes to memento * Grammar fixes for observer * Update explanation for the prototype pattern * Proxy pattern grammar fixes * Update singleton * Grammar fixes to state pattern * Grammar fixes for strategy * Grammar fixes, template method * Grammar fixes for visitor * Fix typo
187 lines
4.8 KiB
Markdown
187 lines
4.8 KiB
Markdown
---
|
|
layout: pattern
|
|
title: Memento
|
|
folder: memento
|
|
permalink: /patterns/memento/
|
|
categories: Behavioral
|
|
language: en
|
|
tags:
|
|
- Gang of Four
|
|
---
|
|
|
|
## Also known as
|
|
|
|
Token
|
|
|
|
## Intent
|
|
|
|
Without violating encapsulation, capture and externalize an object's internal state so that the
|
|
object can be restored to this state later.
|
|
|
|
## Explanation
|
|
|
|
Real-world example
|
|
|
|
> We are working on an astrology application where we need to analyze star properties over time. We
|
|
> are creating snapshots of star states using the Memento pattern.
|
|
|
|
In plain words
|
|
|
|
> Memento pattern captures object internal state making it easy to store and restore objects in any
|
|
> point of time.
|
|
|
|
Wikipedia says
|
|
|
|
> The memento pattern is a software design pattern that provides the ability to restore an object to
|
|
> its previous state (undo via rollback).
|
|
|
|
**Programmatic Example**
|
|
|
|
Let's first define the types of stars we are capable to handle.
|
|
|
|
```java
|
|
public enum StarType {
|
|
SUN("sun"),
|
|
RED_GIANT("red giant"),
|
|
WHITE_DWARF("white dwarf"),
|
|
SUPERNOVA("supernova"),
|
|
DEAD("dead star");
|
|
...
|
|
}
|
|
```
|
|
|
|
Next, let's jump straight to the essentials. Here's the `Star` class along with the mementos that we
|
|
need to manipulate. Especially pay attention to `getMemento` and `setMemento` methods.
|
|
|
|
```java
|
|
public interface StarMemento {
|
|
}
|
|
|
|
public class Star {
|
|
|
|
private StarType type;
|
|
private int ageYears;
|
|
private int massTons;
|
|
|
|
public Star(StarType startType, int startAge, int startMass) {
|
|
this.type = startType;
|
|
this.ageYears = startAge;
|
|
this.massTons = startMass;
|
|
}
|
|
|
|
public void timePasses() {
|
|
ageYears *= 2;
|
|
massTons *= 8;
|
|
switch (type) {
|
|
case RED_GIANT:
|
|
type = StarType.WHITE_DWARF;
|
|
break;
|
|
case SUN:
|
|
type = StarType.RED_GIANT;
|
|
break;
|
|
case SUPERNOVA:
|
|
type = StarType.DEAD;
|
|
break;
|
|
case WHITE_DWARF:
|
|
type = StarType.SUPERNOVA;
|
|
break;
|
|
case DEAD:
|
|
ageYears *= 2;
|
|
massTons = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
StarMemento getMemento() {
|
|
var state = new StarMementoInternal();
|
|
state.setAgeYears(ageYears);
|
|
state.setMassTons(massTons);
|
|
state.setType(type);
|
|
return state;
|
|
}
|
|
|
|
void setMemento(StarMemento memento) {
|
|
var state = (StarMementoInternal) memento;
|
|
this.type = state.getType();
|
|
this.ageYears = state.getAgeYears();
|
|
this.massTons = state.getMassTons();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return String.format("%s age: %d years mass: %d tons", type.toString(), ageYears, massTons);
|
|
}
|
|
|
|
private static class StarMementoInternal implements StarMemento {
|
|
|
|
private StarType type;
|
|
private int ageYears;
|
|
private int massTons;
|
|
|
|
// setters and getters ->
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
And finally here's how we use the mementos to store and restore star states.
|
|
|
|
```java
|
|
var states = new Stack<>();
|
|
var star = new Star(StarType.SUN, 10000000, 500000);
|
|
LOGGER.info(star.toString());
|
|
states.add(star.getMemento());
|
|
star.timePasses();
|
|
LOGGER.info(star.toString());
|
|
states.add(star.getMemento());
|
|
star.timePasses();
|
|
LOGGER.info(star.toString());
|
|
states.add(star.getMemento());
|
|
star.timePasses();
|
|
LOGGER.info(star.toString());
|
|
states.add(star.getMemento());
|
|
star.timePasses();
|
|
LOGGER.info(star.toString());
|
|
while (states.size() > 0) {
|
|
star.setMemento(states.pop());
|
|
LOGGER.info(star.toString());
|
|
}
|
|
```
|
|
|
|
Program output:
|
|
|
|
```
|
|
sun age: 10000000 years mass: 500000 tons
|
|
red giant age: 20000000 years mass: 4000000 tons
|
|
white dwarf age: 40000000 years mass: 32000000 tons
|
|
supernova age: 80000000 years mass: 256000000 tons
|
|
dead star age: 160000000 years mass: 2048000000 tons
|
|
supernova age: 80000000 years mass: 256000000 tons
|
|
white dwarf age: 40000000 years mass: 32000000 tons
|
|
red giant age: 20000000 years mass: 4000000 tons
|
|
sun age: 10000000 years mass: 500000 tons
|
|
```
|
|
|
|
## Class diagram
|
|
|
|

|
|
|
|
## Applicability
|
|
|
|
Use the Memento pattern when
|
|
|
|
* A snapshot of an object's state must be saved so that it can be restored to that state later, and
|
|
* A direct interface to obtaining the state would expose implementation details and break the
|
|
object's encapsulation
|
|
|
|
## Known uses
|
|
|
|
* [java.util.Date](http://docs.oracle.com/javase/8/docs/api/java/util/Date.html)
|
|
|
|
## Credits
|
|
|
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
|
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|