I am currently trying to implement some design patterns in Kotlin as an exercise and I'm a bit stuck with the 'Memento' pattern. My reference resource is SourceMaking: Memento.
I want to implement this structure:
While following their "Checklist"
I can't get step 5 to work. How do I make a Memento
object whose fields can be read from inside the Originator
instance but that is completely opaque to the Caretaker
?
I have successfully implemented this in Java as follows:
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;
}
}
}
And a Caretaker
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);
}
}
Because they are inner classes I can read the private fields of Memento
and State
from my Originator
instance, but to the Caretaker
my Memento
instance is completely opaque (only showing Object
s member functions).
Now how do I implement this exact behavior in Kotlin? Basically I am missing the functionality of reading private fields of inner classes.
The closest thing I could think of was this:
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)
}
This has the desired effect of Memento
being completely opaque to my Caretaker
instance, but I can't read the fields from within Originator
either.
This code by the way is almost exactly the same as the generated code produced by the 'Convert Java to Kotlin' feature of IntelliJ applied to my Java code (and it obviously doesn't compile either).
So is there something obvious (or magical) I am missing here? Maybe something other than the structure displayed in the class diagram? Or can these exact specifications just not be implemented in Kotlin?
And on another note: Is the requirement of opaqueness for the Memento object actually a colloquially accepted property of the Memento Pattern or did SourceMaking come up with this requirement?
You can define a public parent class for Memento
and a private inheritor class for it:
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
}
}
The implementation class is private
, and, outside Originator
, the instances will only be seen as Memento
(see the function signatures), so that the state won't be accessible.