备忘录模式的缺点

3

这里是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方法)。
有没有办法克服这个问题呢? 或者说,我是否过于关注细节,这些细节并不重要?
1个回答

4

1)注意,Caretaker 应该负责保管备忘录,而不一定要负责撤销/重做。如果你查看互联网上的各种实现(例如这里),你会发现 Caretaker 没有 revert(),而通常是像 getMemento() 这样的方法。因此,负责撤销操作的类是另外一个类,它在 Caretaker 上调用 getMemento() 然后在 Subject 上调用 revert()

即使你想让 Caretaker 负责撤销操作,也请注意 employee.revert() 是一个专门为 caretaker.revert() 创建的方法,因为在这个设计中,没有其他人可以访问备忘录。你可以将其可见性降低,只对 Caretaker 可见。(如果这是 C++,使用 friend 就很容易实现,但在 Java 中,你必须有创意地使用 package 可见性或其他方式。)

2)在备忘录模式中,一个类及其备忘录是紧密耦合的。实际上,只有该类本身才能访问备忘录的内部,其他人不应该看到备忘录的组成方式。因此,如果对类进行更改,则其备忘录是否发生更改并不重要。

然而,如果你想隔离更改,也可以有创意地解决问题。例如,不是在 Class 和其备忘录中都复制 namephone,而是提取另一个包含这些字段的类(假设名为 State),然后在原始类和其备忘录中都使用这个 State。这样,当类的状态发生更改时,只需修改 State

顺带说一下:最好将备忘录定义为 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());
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接