我目前正在尝试在Kotlin中实现一些设计模式作为练习,而且我对'Memento'模式有点困惑。我的参考资源是SourceMaking: 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 Pattern的通俗接受属性,还是SourceMaking是否提出了这个要求?
答案 0 :(得分:2)
您可以为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
(请参阅函数签名),以便状态不可访问
答案 1 :(得分:0)
您应该使用包级访问权限定义Memento
类属性。