纪念品模式的缺点

时间:2016-06-04 05:54:51

标签: java oop design-patterns

所以,这是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());
    }
}

我发现的这种模式的所有实现都或多或少与上面的实现相同。但是这种实现存在一些问题,我不喜欢:

  1. 可以对employee.revert()caretaker.revert(employee)进行调整。我想只有一个接入点。
  2. 如果我们想要更改EmployeeMemento,我们还必须在Employee类中进行更改(因为revert方法)。
  3. 有没有办法克服这个问题? 或者我可能会过多关注,而这些细节并不那么重要?

1 个答案:

答案 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中复制namephone,而是可以提取另一个包含这些字段的类(比如State的名称),然后使用此{原始类及其纪念品中的{1}}。这样,当您更改了类的状态时,您只需要修改State

旁注:最好将Memento定义为主题内的嵌套静态类。

所以我的设计,解决你的问题,将是这样的:

State