或称
标记
目的
在不违反封装的情况下,捕获并外部化对象的内部状态,以便以后可以将对象恢复到该状态。
解释
真实世界例子
我们正在开发一个占星术应用程序,需要分析恒星随时间变化的特性。我们正在使用Memento模式创建恒星状态的快照。
通俗地说
Memento模式捕获对象的内部状态,便于在任何时间点存储和恢复对象。
维基百科说
Memento模式是一种软件设计模式,提供将对象恢复到其先前状态的能力(通过回滚撤消)。
程序示例
让我们首先定义我们能够处理的恒星类型。
java
public enum StarType {
SUN("sun"),
RED_GIANT("red giant"),
WHITE_DWARF("white dwarf"),
SUPERNOVA("supernova"),
DEAD("dead star");
...
}接下来,让我们直接跳到要点。这是 Star 类以及我们需要处理的mementos。尤其要注意 getMemento 和 setMemento 方法。
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 ->
...
}
}最后是我们如何使用mementos来存储和恢复恒星状态。
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());
}程序输出:
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类图

适用性
在以下情况下使用Memento模式
- 必须保存对象状态的快照,以便以后可以将其恢复到该状态
- 获取状态的直接接口将公开实现细节并破坏对象的封装