如何在Kotlin中实现Memento模式

时间:2017-08-24 16:45:18

标签: java design-patterns kotlin memento

我目前正在尝试在Kotlin中实现一些设计模式作为练习,而且我对'Memento'模式有点困惑。我的参考资源是SourceMaking: Memento

我想实现这个结构:

Class diagram of 'Memento' Design Pattern

遵循他们的“清单”

  1. 确定“看护人”和“发起人”的角色。
  2. 创建一个Memento类并将发起者声明为朋友。
  3. 看守者知道何时“检查点”发端人。
  4. Originator创建纪念品并将其状态复制到该Memento。
  5. 看守人坚持(但不能偷看)纪念品。
  6. 看守者知道何时“回滚”发端人。
  7. Originator使用Memento中保存的状态恢复自身。
  8. 我无法让第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实例中读取StateOriginator的私有字段,但是可以读取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是否提出了这个要求?

2 个答案:

答案 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类属性。