0

我目前正在尝试在 Kotlin 中实现一些设计模式作为练习,但我有点坚持使用“Memento”模式。我的参考资源是SourceMaking: Memento

我想实现这个结构:

'Memento' 设计模式的类图

在遵循他们的“清单”时

  1. 确定“看守人”和“发起人”的角色。
  2. 创建一个 Memento 类并将创建者声明为朋友。
  3. 看守者知道何时“检查点”发起者。
  4. Originator 创建一个 Memento 并将其状态复制到该 Memento。
  5. 看守人抓住(但不能窥视)纪念品。
  6. 看守者知道何时“回滚”发起者。
  7. Originator 使用 Memento 中保存的状态恢复自身。

我无法让第 5 步工作。如何制作一个Memento对象,其字段可以从Originator实例内部读取,但对Caretaker?

我已经在 J​​ava 中成功实现了这一点,如下所示:

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,但对于我的实例来说是完全不透明的(仅显示s 成员函数)。StateOriginatorCaretakerMementoObject

现在我如何在 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 提出了这个要求?

4

2 回答 2

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(参见函数签名),因此无法访问状态。

于 2017-08-24T17:07:23.740 回答
0

您应该Memento使用包级访问定义您的类属性。

于 2017-08-24T16:58:28.593 回答