所以,这是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
方法)。有没有办法克服这个问题? 或者我可能会过多关注,而这些细节并不那么重要?
答案 0 :(得分:4)
1)请注意,Caretaker应该照顾Mementos,不一定要照顾Undo / Redo。如果您查看Internet上的各种实现(例如here),您会发现Caretaker没有revert()
,但通常是getMemento()
。因此,负责撤消的班级是其他人在看守者上调用getMemento()
然后在主题上调用revert()
。
即使您希望Caretaker负责撤消,请注意employee.revert()
是一种仅由caretaker.revert()
创建的方法,因为在此设计中,没有其他人可以访问Mementos。您可以通过Caretaker降低其可见性。 (如果这是C ++,可以通过friend
轻松完成,但在Java中,您必须具有创造性并使用package
可见性或其他方式。)
2)在Memento模式中,一个类及其Memento紧密耦合。实际上,只有班级本身可以访问Memento的内部,没有人应该看到Memento是如何组成的。因此,如果对类的更改传播到其Memento并不重要。
然后再次如果您要隔离更改,您可以再次创作。例如,不是在Class及其Memento中复制name
和phone
,而是可以提取另一个包含这些字段的类(比如State
的名称),然后使用此{原始类及其纪念品中的{1}}。这样,当您更改了类的状态时,您只需要修改State
。
旁注:最好将Memento定义为主题内的嵌套静态类。
所以我的设计,解决你的问题,将是这样的:
State