3

我正在对纪念品模式进行一些研究,似乎我遇到的大多数示例似乎都比较相似(将字符串保存到数组中并在需要时恢复它)如果我错了,现在纠正我,但我相信我刚刚描述的方法是“对象克隆”,但是实现备忘录模式的其他方法是什么?

从我也了解到可以使用序列化,但似乎有一个灰色区域,人们说它违反了对象的封装,因此不是实现 Memento 模式的方法。

那么任何人都能够阐明实现该模式的方法吗?我的研究提出了一种所有不同事物的混合体,只是让一切变得混乱。

谢谢

4

2 回答 2

4

memento 实现可能带来的一个常见问题是,通常需要许多类来表示不同类型对象的内部状态。或者 memento 实现必须将对象状态序列化为其他形式(例如序列化的 java 对象)。

这是一个备忘录实现的草图,它不依赖于每个类的特定备忘录类,其状态将被捕获以支持撤消/重做。

首先要介绍一个基本概念:

public interface Reference<T> {
    T get();
    void set(T value);
}

这是 的抽象java.lang.ref.Reference,因为该类用于垃圾收集目的。但是我们需要将它用于业务逻辑。基本上,引用封装了一个字段。所以他们打算这样使用:

public class Person {
    private final Reference<String> lastName;
    private final Reference<Date> dateOfBirth;

    // constructor ...

    public String getLastName() {
        return lastName.get();
    }

    public void setLastName(String lastName) {
        this.lastName.set(lastName);
    }

    public Date getDateOfBirt() {
        return dateOfBirth.get();
    }

    public void setDateOfBirth(Date dateOfBirth) {
        this.dateOfBirth.set(dateOfBirth);
    }
}

请注意,使用这些引用进行对象实例化可能不是那么简单,但我们将其留在这里。

现在这里是 memento 实现的详细信息:

public interface Caretaker {

    void addChange(Change change);
    void undo();
    void redo();
    void checkpoint();   
}

public interface Change {

    Change createReversal();
    void revert();
}

基本上 aChange表示对可识别对象状态的单个可识别更改。Change通过调用方法可以恢复A revert,并且可以通过恢复由createReversal方法创建的 Change 来恢复该更改的反转。通过该方法Caretaker累积对对象状态的更改addChange。通过调用undoandredo方法,Caretaker恢复或重做(即恢复更改的反转)所有更改,直到到达下一个检查点。检查点表示所有观察到的更改将累积到将所有更改对象的所有状态从一个有效配置转换为另一个有效配置的更改的点。检查点通常在操作之前或之前创建。这些是通过创建的checkpoint方法。

现在这里是如何使用Caretakerwith Reference

public class ReferenceChange<T> implements Change {

    private final Reference<T> reference;
    private final T oldValue;
    private final T currentReferenceValue;

    public ReferenceChange(Reference<T> reference, T oldValue,
            T currentReferenceValue) {
        super();
        this.reference = reference;
        this.oldValue = oldValue;
        this.currentReferenceValue = currentReferenceValue;
    }

    @Override
    public void revert() {
        reference.set(oldValue);
    }

    @Override
    public Change createReversal() {
        return new ReferenceChange<T>(reference, currentReferenceValue,
                oldValue);
    }
}

public class CaretakingReference<T> implements Reference<T> {

    private final Reference<T> delegate;
    private final Caretaker caretaker;

    public CaretakingReference(Reference<T> delegate, Caretaker caretaker) {
        super();
        this.delegate = delegate;
        this.caretaker = caretaker;
    }

    @Override
    public T get() {
        return delegate.get();
    }

    @Override
    public void set(T value) {
        T oldValue = delegate.get();
        delegate.set(value);
        caretaker.addChange(new ReferenceChange<T>(delegate, oldValue, value));
    }
}

存在Change表示 a 的值如何Reference变化的 a。这Change是在CaretakingReference设置时创建的。在这个实现中,需要嵌套ReferenceCaretakingReference实现中,因为 arevertReferenceChange应该addChange通过CaretakingReference.

集合属性不需要使用Reference. 在这种情况下,应该使用触发照顾的自定义实现。基元可以与自动装箱一起使用。

此实现通过始终使用引用而不是直接使用字段来推断额外的运行时和内存成本。

于 2013-01-07T19:14:26.230 回答
4

Java Collections 框架定义了Queue,它可以提供帮助。

候选代码:

public final class Memento<T>
{
    // List of saved values
    private final Queue<T> queue = new ArrayDeque<T>();

    // Last entered value, whether it has been saved or not
    private T currentValue;

    // No initial state, ie currentValue will be null on construction, hence
    // no constructor

    // Set a value, don't save it
    public void set(final T value)
    {
        currentValue = value;
    }

    // Persist the currently saved value
    public void persist()
    {
        queue.add(currentValue);
    }

    // Return the last saved value
    public T lastSaved()
    {
        return queue.element();
    }

    // Return the last entered value
    public T lastEntered()
    {
        return currentValue;
    }
}

这段代码中明显缺少很多东西,但很容易实现:

  • 恢复到上次保存的值;
  • 不检查空值;
  • T不执行Serializable
  • 便捷方法(例如,添加一个值并使其成为最后保存的状态);
  • 代码不是线程安全的

等等。

示例代码:

public static void main(final String... args)
{
    final Memento<String> memento = new Memento<String>();

    memento.set("state1");
    System.out.println(memento.lastEntered()); // "state1"
    memento.persist();
    memento.set("state2");
    System.out.println(memento.lastEntered()); // "state2"
    System.out.println(memento.lastSaved()); // "state1"
}

实际上:这是一个可以改进的脑死实现,但可以用作基础——扩展它取决于您的需要;)

于 2012-12-29T15:30:26.710 回答