因此,这是Memento模式的典型实现(跳过的getter和setter)。
public class Employee {
private String name;
private String phone;
public EmployeeMemento save() {
return new EmployeeMemento(name, phone);
}
public void revert(EmployeeMemento memento) {
this.name = memento.getName();
this.phone = memento.getPhone();
}
}
public class EmployeeMemento {
private final String name;
private final String phone;
public EmployeeMemento(String name, String phone) {
this.name = name;
this.phone = phone;
}
}
public class Caretaker {
private Stack<EmployeeMemento> history;
public Caretaker() {
history = new Stack<>();
}
public void save(Employee employee) {
history.push(employee.save());
}
public void revert(Employee employee) {
employee.revert(history.pop());
}
}
我发现此模式的所有实现都或多或少等于上述模式。但是这种实现方式存在一些我不喜欢的问题:
employee.revert()
和caretaker.revert(employee)
。我只想有一个接入点。 revert
方法)。 有办法克服吗?
还是我太在意,而这个细节不是那么重要?
最佳答案
1)请注意,看守员应该照顾持有Mementos,而不必照顾撤消/重做。如果查看Internet上的各种实现(例如here),您会看到Caretaker没有revert()
,但通常带有getMemento()
之类的东西。因此,负责Undoing的类是在Caretaker上调用getMemento()
,然后在Subject上调用revert()
的其他人。
即使您希望Caretaker负责撤消操作,也请注意employee.revert()
是caretaker.revert()
专门创建的一种方法,因为在此设计中,没有其他人可以访问Mementos。您可以降低其可见性,使其仅由看守人可见。 (如果这是C++,则可以使用friend
轻松完成,但是在Java中,您必须具有创造力,并使用package
可见性或其他方式。)
2)在Memento模式中,一个类及其Memento是紧密耦合的。实际上,只有 class 本身可以访问Memento的内部,没有其他人可以看到Memento的组成。因此,对类的更改是否传播到其Memento都没有关系。
再然后,如果您想隔离更改,则可以再次发挥创意。例如,除了提取Class和其Memento中的name
和phone
外,您还可以提取另一个包含这些字段的类(以State
的名称为例),然后在原始类及其Memento中使用此State
。这样,当您更改类的状态时,只需要修改State
即可。
旁注:最好将Memento定义为Subject内部的嵌套静态类。
所以我的设计可以解决您的问题,就像这样:
public class Employee {
private State state;
public Memento save() {
return new Memento(state);
}
public void revert(Memento memento) {
this.state = memento.state;
}
public static class Memento {
private final State state;
public Memento(State state) {
this.state = state;
}
}
public static class State {
private String name;
private String phone;
}
}
public class Caretaker {
private Stack<Employee.Memento> history;
public Caretaker() {
history = new Stack<>();
}
public void addMemento(Employee.Memento memento) {
history.push(memento);
}
public Employee.Memento getMemento() {
return history.pop();
}
}
public class UndoHandler {
Employee employee;
Caretaker caretaker;
public void snapshot() {
caretaker.save(employee.save());
}
public void undo() {
employee.revert(caretaker.getMemento());
}
}