文章目录
【Java设计模式】备忘录模式
一、概述
Java中的备忘录设计模式允许开发人员捕获和恢复对象的内部状态,而不违反封装。
二、详细解释及实际示例
- 实际示例:
- 一个文本编辑器应用程序可以利用Java中的备忘录设计模式来实现撤销和重做功能。通过在每次进行更改时将文档的当前状态捕获为备忘录,应用程序可以轻松地将文档恢复到任何以前的状态。这些快照存储在历史列表中。当用户点击撤销按钮时,编辑器将文档恢复到最近的备忘录中保存的状态。这个过程允许用户恢复到文档的以前版本,而无需暴露或更改编辑器的内部数据结构。
- 通俗解释:
- 备忘录模式捕获对象的内部状态,使其易于在任何时间点存储和恢复对象。
- 维基百科解释:
- 备忘录模式是一种软件设计模式,它提供了将对象恢复到其以前状态(通过回滚撤销)的能力。
三、Java中备忘录模式的编程示例
在我们的占星学应用程序中,我们使用备忘录模式来捕获和恢复星星对象的状态。每个状态都被保存为一个备忘录,允许我们根据需要恢复到以前的状态。
首先,让我们定义我们能够处理的星星类型。
public enum StarType {
SUN("sun"),
RED_GIANT("red giant"),
WHITE_DWARF("white dwarf"),
SUPERNOVA("supernova"),
DEAD("dead star");
//...
}
接下来,让我们直接跳到关键部分。这是Star
类以及我们需要操作的备忘录。特别注意getMemento
和setMemento
方法。
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;
case SUN -> type = StarType.RED_GIANT;
case SUPERNOVA -> type = StarType.DEAD;
case WHITE_DWARF -> type = StarType.SUPERNOVA;
case DEAD -> {
ageYears *= 2;
massTons = 0;
}
default -> {
}
}
}
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 ->
//...
}
}
最后,这是我们如何使用备忘录来存储和恢复星星状态的示例。
public static void main(String[] args) {
var states = new Stack<StarMemento>();
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.isEmpty()) {
star.setMemento(states.pop());
LOGGER.info(star.toString());
}
}
程序输出:
14:09:15.878 [main] INFO com.iluwatar.memento.App -- sun age: 10000000 years mass: 500000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- red giant age: 20000000 years mass: 4000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- white dwarf age: 40000000 years mass: 32000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- supernova age: 80000000 years mass: 256000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- dead star age: 160000000 years mass: 2048000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- supernova age: 80000000 years mass: 256000000 tons
14:09:15.880 [main] INFO com.iluwatar.memento.App -- white dwarf age: 40000000 years mass: 32000000 tons
14:09:15.881 [main] INFO com.iluwatar.memento.App -- red giant age: 20000000 years mass: 4000000 tons
14:09:15.881 [main] INFO com.iluwatar.memento.App -- sun age: 10000000 years mass: 500000 tons
四、何时在Java中使用备忘录模式
当以下情况时使用备忘录模式:
- 您需要在Java中捕获对象的状态并在以后恢复它,而不暴露其内部结构。这对于维护封装和简化对象状态的管理至关重要。
- 直接获取状态的接口将暴露实现细节并破坏对象的封装。
五、备忘录模式在Java中的实际应用
备忘录模式在各种Java应用程序中使用,包括java.util.Date
和java.util.Calendar
类,它们可以恢复到以前的状态。它在文本编辑器和图形编辑器的撤销机制中也很常见。
六、备忘录模式的好处和权衡
好处:
- 保留封装边界。
- 通过消除直接管理版本历史或撤销功能的需求,简化了发起者。
权衡:
- 如果保存大量状态,可能会在内存方面昂贵。
- 必须注意管理备忘录的生命周期,以避免内存泄漏。