因此,這是Memento模式的典型實現(xiàn)(跳過的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()); }}
我發(fā)現(xiàn)此模式的所有實現(xiàn)都或多或少等于上述模式.但是這種實現(xiàn)方式存在一些我不喜歡的問題:
>可能會同時觸發(fā)employee.revert()和caretaker.revert(employee).我只想有一個接入點.
>如果要更改EmployeeMemento,則還必須在Employee類中進行更改(由于revert方法).
有辦法克服嗎?
還是我太在意,而這個細節(jié)不是那么重要?
解決方法:
1)請注意,看守員應該照顧持有Mementos,而不必照顧撤消/重做.如果您查看Internet上的各種實現(xiàn)(例如here),您會看到Caretaker沒有revert(),但通常具有諸如getMemento()之類的東西.因此,負責Undoing的類是在Caretaker上調(diào)用getMemento()然后在Subject上調(diào)用revert()的其他人.
即使您希望Caretaker負責撤消操作,也請注意,employee.revert()是一種僅由caretaker.revert()使用的方法,因為在此設計中,沒有其他人可以訪問Mementos.您可以降低其可見性,使其僅由看守人可見. (如果是C,則可以通過使用friend輕松完成,但是在Java中,您必須具有創(chuàng)造力,并使用包可見性或其他方式.)
2)在Memento模式中,一個類及其Memento是緊密耦合的.實際上,只有班級本身可以訪問Memento的內(nèi)部,沒有其他人可以看到Memento的組成.因此,對類的更改是否傳播到其Memento都沒有關系.
再然后,如果您想隔離更改,則可以再次發(fā)揮創(chuàng)造力.例如,您可以提取包含這些字段的另一個類(用State的名字說),而不是在Class和其Memento中復制名稱和電話,然后在原始類及其Memento中使用該State.這樣,當您更改類的狀態(tài)時,只需修改State.
旁注:最好將Memento定義為Subject內(nèi)部的嵌套靜態(tài)類.
所以我的設計可以解決您的問題,就像這樣:
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()); }}