我目前正在尝试在Kotlin中实现一些设计模式作为练习,而我对“ Memento”模式有些犹豫。我的参考资源是SourceMaking: Memento。
我想实现这种结构:
在遵循他们的“清单”时
确定“看守人”和“发起人”的角色。
创建一个Memento类,并将创建者声明为朋友。
看守知道何时“检查点”发起者。
发起者创建一个Memento,并将其状态复制到该Memento。
看守人坚持(但不能窥视)纪念品。
看守知道何时“回滚”发起者。
发起者使用Memento中的保存状态恢复自身。
我无法执行步骤5。我该如何创建一个Memento
对象,其对象的字段可以从Originator
实例内部读取,但对于Caretaker
来说是完全不透明的?
我已经在Java中成功实现了以下步骤:
public class Originator {
private final int id;
private String title;
private String description;
public Originator(int id) {
this.id = id;
}
/* skipping title and description getter & setter */
public Memento saveState() {
return new Memento(new State(id, title, description));
}
public void restore(Memento memento) {
id = memento.state.id;
title = memento.state.title;
description = memento.state.description;
}
private class State {
private final int id;
private final String title;
private final String description;
public State(int id, String title, String description) {
this.id = id;
this.title = title;
this.description = description;
}
}
public class Memento {
private final State state;
public Memento(State state) {
this.state = state;
}
}
}
还有看守
public class Caretaker {
public Originator originator;
public Caretaker(@NotNull Originator originator) {
this.originator = originator;
}
public Originator.Memento save() {
return originator.saveState();
}
public void restore(@NotNull Originator.Memento memento) {
originator.restoreFromState(memento);
}
}
因为它们是内部类,所以我可以从我的
Memento
实例读取State
和Originator
的私有字段,但是对于Caretaker
我的Memento
实例是完全不透明的(仅显示Object
成员函数) 。现在如何在Kotlin中实现这种确切的行为?基本上,我缺少读取内部类的私有字段的功能。
我能想到的最接近的是:
class Originator(id: Long) {
private var id: Long = id
var description: String = ""
var title: String = ""
fun saveState() = Memento(State(id, title, description))
fun restoreState(memento: Memento) {
id = memento.state.id // <-- cannot access 'state': it is private in 'Memento'
title = memento.state.title // <-- cannot access 'state': it is private in 'Memento'
description = memento.state.description // <-- cannot access 'state': it is private in 'Memento'
}
inner class State(private val id: Long,
private val title: String,
private val description: String)
inner class Memento(private val state: State)
}
这具有
Memento
对我的Caretaker
实例完全不透明的理想效果,但是我也无法从Originator
中读取字段。顺便说一下,这段代码与应用于我的Java代码的IntelliJ的“将Java转换为Kotlin”功能生成的生成代码几乎完全相同(显然,它们也不编译)。
那么,我在这里缺少什么明显的(或神奇的)东西吗?也许除了类图中显示的结构以外的其他内容?还是不能在Kotlin中实施这些确切的规范?
另一个要注意的是:对Memento对象的不透明度要求是否实际上是Memento模式的通俗接受属性,还是SourceMaking提出了这一要求?
最佳答案
您可以为Memento
定义一个公共父类,并为其定义一个私有继承者类:
class Originator {
/* irrelevant declarations skipped */
abstract inner class Memento
private inner class MementoImpl(val state: State) : Memento()
fun saveState(): Memento {
return MementoImpl(State(id, title, description))
}
fun restore(memento: Memento) {
memento as MementoImpl
id = memento.state.id
title = memento.state.title
description = memento.state.description
}
}
实现类为
private
,并且在Originator
之外,实例将仅被视为Memento
(请参见函数签名),因此状态将不可访问。