设计模式——备忘录模式

本文介绍备忘录模式。

概念

在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。

结构和工作原理

  • 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

Author: nopainanymore
Link: http://nopainanymore.me/DesignPattern-Memento/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
wechat