1

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:

Class diagram of 'Memento' Design Pattern

While following their "Checklist"

  1. Identify the roles of “caretaker” and “originator”.
  2. Create a Memento class and declare the originator a friend.
  3. Caretaker knows when to "check point" the originator.
  4. Originator creates a Memento and copies its state to that Memento.
  5. Caretaker holds on to (but cannot peek into) the Memento.
  6. Caretaker knows when to "roll back" the originator.
  7. Originator reinstates itself using the saved state in the Memento.

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 Objects 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?

Daniel W.
  • 623
  • 6
  • 14

2 Answers2

2

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.

hotkey
  • 140,743
  • 39
  • 371
  • 326
  • Nice! Didn't think about that. How would you rate the solution though? Is this how it should be done in your opinion, or is there maybe a different way, more removed from the java example but maybe better Kotlin code? What I'm trying to say is, in a code review would you give a thumbs up or would you be sceptical about that empty interface? – Daniel W. Aug 24 '17 at 17:29
  • My initial scepticism probably stems from the fact that I like to think of interfaces more as a thing describing what something *does* and not what something *is*. And in this case it's mostly used to hack around the type system, no? Not trying to be a smart ass here. It's a practical solution, works nicely, and I would probably use it in production. But since I'm still learning and doing this as an exercise to better understand the language, I just want to know if you'd say this is the "kotlin way" to do it in your opinion – Daniel W. Aug 24 '17 at 17:35
  • 1
    I rather agree it's a hack for the visibility system which does not allow members of a class to be visible to certain classes (apart from the subclasses -- there's `protected`, useless here though) - in Kotlin, there's no `friend` visibility that the pattern requires. In Java, the enclosing class can access the private members, and that's enough for this pattern. Actually, a bigger problem that I see with the interface is that it can be implemented by a different class. I've edited the answer, now it's an `abstract inner class`, so that it can't be inherited outside the scope of `Originator`. – hotkey Aug 24 '17 at 18:03
  • Yes! I was just thinking about that myself. The nice thing about the original java example was that only the `Originator` could ever define its state instances. Now it behaves exactly the same. Thanks! – Daniel W. Aug 24 '17 at 18:41
  • @DanielW. If your code does work, and you'd like additional feedback you should head to [codereview.se] – Mibac Aug 24 '17 at 20:22
  • If I wanted to serialize the memento in order to restore the state after an application restart, how would this work? – Bennik2000 Jul 30 '22 at 08:06
0

You should define your Memento class properties with package-level access.

alirabiee
  • 1,286
  • 7
  • 14
  • 2
    Kotlin does not have package-level access. There's only `internal` for module-level access. – hotkey Aug 24 '17 at 16:59
  • 1
    I don't think `internal` is the right way to do this...and neither would be package private access like in Java. Because then I'd have to organize my package, or even worse, module structure according to my field visibility needs. This to me would seem more like a hack... – Daniel W. Aug 24 '17 at 17:08