本文介绍备忘录模式。
概念
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
结构和工作原理
- Originator:原始对象
- Memento:备忘录,负责存储原始对象的状态
- Caretaker:备忘录管理类,负责保存好备忘录
备忘录模式就是在不破坏对象封装性的前提下,捕获一个对象的内部状态,并在该对象之外将其保存,在之后需要恢复的时候将保存状态进行还原。
备忘录模式有三类对象,Originator
为持有需要保存状态的对象,Memento
为保存Originator
状态的对象,Caretaker
用来管理保存Memento
对象。Origination
对象可以通过调用Memento
提供的方法对自身的状态进行保存生成一个新的Memento
对象,同时也可以接受一个Memento
对象,把自身状态覆盖成Memento
记录的状态;Memento
对象只负责记录Originator
的状态;Caretaker
则负责对Memento
提供存储和获取的功能。
优点:
- 为对象提供了回滚的机制
- 实现了信息的封装,对客户端屏蔽了状态保存的过程
缺点:
为了节省内存,可使用原型模式与备忘录模式组合使用。
代码示例
@Getter @Setter @AllArgsConstructor @NoArgsConstructor @Slf4j public class GameStatus {
private static Gson gson = new Gson();
private String status;
public CheckPoint arriveCheckPoint() { return CheckPoint.of(this.status); }
public void readCheckPoint(CheckPoint checkPoint) { log.info("GameStatus- readCheckPoint- checkPoint:{}", gson.toJson(checkPoint)); this.setStatus(checkPoint.getStatus()); } }
|
@Getter public class CheckPoint {
private static AtomicInteger idGenerator = new AtomicInteger(0);
private Integer id;
private Long epochMilliSecond;
private String status;
private CheckPoint(String status) { this.id = idGenerator.incrementAndGet(); this.status = status; this.epochMilliSecond = System.currentTimeMillis(); }
public static CheckPoint of(String status) { return new CheckPoint(status); } }
|
public class Archive {
private Map<Integer, CheckPoint> checkPointMap = new HashMap<>();
public void addCheckPoint(CheckPoint checkPoint) { checkPointMap.put(checkPoint.getId(), checkPoint); }
public Optional<CheckPoint> getCheckPoint(Integer id) { return Optional.of(checkPointMap.get(id)); } }
|
@Slf4j public class MementoClient {
private static Gson gson = new Gson();
public static void main(String[] args) { Archive archive = new Archive();
List<GameStatus> statuses = IntStream .range(1, 9) .mapToObj(level -> new GameStatus("Level" + " " + level)) .collect(Collectors.toList()); statuses .forEach(status -> archive.addCheckPoint(status.arriveCheckPoint()));
GameStatus readCheckPoint = new GameStatus();
archive.getCheckPoint(1).ifPresent(readCheckPoint::readCheckPoint); log.info("MementoClient- main- readCheckPoint:{}", gson.toJson(readCheckPoint)); } }
|
参考资料
https://github.com/CyC2018/CS-Notes/blob/master/notes/设计模式 - 备忘录.md
https://www.runoob.com/design-pattern/memento-pattern.html