我正在对Memento模式进行一些研究,似乎我遇到的大多数示例似乎都相对相似(将一个字符串保存到数组中并在需要时恢复它)现在纠正我,如果我错了但是我相信我刚才描述的方法是“对象克隆”,但实现Memento模式的其他方法是什么?
我可以使用序列化中提到的内容,但似乎有一个灰色区域,人们说它违反了对象的封装,并且不是因为这个而实现Memento Pattern的方法。 / p>
那么任何人都可以对实施模式的方法有所了解吗?我的研究得出了各种不同的东西,并且让一切变得混乱。
由于
答案 0 :(得分: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"
}
实际上:这是一个可以改进的脑卒中实现,但可以作为基础 - 扩展它取决于你的需要;)
答案 1 :(得分:4)
memento实现可能遇到的一个常见问题是,通常需要很多表示不同类型对象的内部状态的类。或者memento实现必须将对象状态序列化为其他形式(例如,序列化的java对象)。
这是memento实现的草图,它不依赖于每个类的特定memento类,其状态将被捕获以进行撤消/重做支持。
首先要介绍一个基本概念:
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);
}
}
请注意,使用这些引用进行对象实例化可能不是那么简单,但我们将其留在这里。
现在,以下是纪念品实施的详细信息:
public interface Caretaker {
void addChange(Change change);
void undo();
void redo();
void checkpoint();
}
public interface Change {
Change createReversal();
void revert();
}
基本上Change
表示对可识别对象状态的单个可识别更改。通过调用Change
方法可以恢复revert
,并且可以通过还原createReversal
方法创建的更改来恢复该更改的撤消。 Caretaker
通过addChange
方法累积对象状态的更改。通过调用undo
和redo
方法,Caretaker
恢复或重做(即恢复更改的反转)所有更改,直到达到下一个检查点。检查点表示所有观察到的更改将累积到一个点,该更改将所有已更改对象的所有状态从一个有效配置转换为另一个有效配置。检查点通常在操作之前或之后创建。这些是通过checkpoint
方法创建的。
现在,这里是如何使用Caretaker
和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
,表示Reference
的值如何变化。设置Change
时会创建此CaretakingReference
。在此实现中,Reference
实现中需要嵌套CaretakingReference
,因为revert
的{{1}}不应通过ReferenceChange
触发新的addChange
CaretakingReference
。
集合属性无需使用Reference
。在这种情况下,应该使用触发看护的自定义实现。基元可以与自动装箱一起使用。
此实现通过始终直接使用引用而不是字段来推断额外的运行时和内存开销。