2017-08-24 17 views
0

私は現在、運動としていくつかのデザインパターンを実装しようとしていますが、私はMementoパターンでちょっと固まっています。私の参照リソースはSourceMaking: Mementoです。Kotlinでメメントパターンを実装する方法

私は、この構造を実装する:

Class diagram of 'Memento' Design Pattern

彼らの "チェックリスト"

  1. は「世話人」と「発信者」の役割を確認し、次ながら。
  2. Mementoクラスを作成し、発信者を友人として宣言します。
  3. Caretakerは発信者をいつチェックポイントするかを知っています。
  4. OriginatorはMementoを作成し、そのMementoにその状態をコピーします。
  5. ケアテイカーはを保有していますが、見ることはできませんメンメントです。
  6. 発信者を「ロールバック」するタイミングをCaretakerが認識しています。
  7. 発信者は、メメント内の保存済み状態を使用して自分自身を元に戻します。

手順5を実行することができません。 Originatorインスタンス内からフィールドを読み取れるが、それはCaretakerに対して完全に不透明なMementoオブジェクトを作成するにはどうすればよいですか?

次のように私が正常に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); 
    } 
} 

彼らは内部クラスなので、私は私のOriginatorインスタンスからMementoStateのプライベートフィールドを読み取ることができます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の 'Convert Java to Kotlin'機能が生成したコードとほぼ同じです(どちらもコンパイルされません)。

私はここに何か明白な(または魔法の)ものがありますか?クラス図に表示される構造以外の何か?あるいは、これらの厳密な仕様はKotlinで実装できませんか?

もう1つの注意点:Mementoオブジェクトの不透明性の要件は実際にメメントパターンの口頭で受け入れられるプロパティか、SourceMakingはこの要件を思い付いたのですか?

答えて

1

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として見られます(参照機能シグニチャ)、状態にアクセスできないようにします。

+0

ニース!それについて考えなかった。あなたはどのようにソリューションを評価しますか?これはあなたの意見でどうやってやるべきか、あるいは多分Javaの例から削除されているかもしれないが多分もっと良いKotlinコードでしょうか?私が言おうとしているのは、コードレビューであなたは親指をかけるか、空のインターフェースについて懐疑的だろうか? –

+0

私の最初の懐疑主義は、おそらく、私は、何かが*何か*ではなく、何か*ではないことを記述するものとしてインターフェースを考えることが好きであるという事実に由来するでしょう。そして、この場合は主にタイプシステムをハックするために使用されますが、そうではありませんか? ここでスマートなお尻にしようとしていません。実用的な解決策であり、うまく動作します。おそらく実稼働環境で使用します。しかし、私はまだ学習し、言語をよりよく理解するための練習としてこれをやっているので、あなたの意見でこれを行うための "コットンの道"であるかどうかを知りたいだけです。 –

+1

クラスのメンバーが特定のクラス(サブクラスとは別に、保護されていて、ここでは役に立たない)から見えるようにする可視性システム - Kotlinでは、パターンに必要な「友人」の可視性はありません。 Javaでは、囲むクラスがプライベートメンバーにアクセスできます。このパターンで十分です。実際に、私がインターフェイスで見るより大きな問題は、それが別のクラスによって実装できるということです。私は答えを編集しました。今は '抽象的な内部クラス 'なので、' Originator'の範囲外に継承することはできません。 – hotkey

0

パッケージレベルのアクセスでクラスプロパティMementoを定義する必要があります。あなたはそれのためにMementoのための公共の親クラスとプライベート相続クラスを定義することができ

+2

Kotlinにはパッケージレベルのアクセス権がありません。モジュールレベルのアクセスには 'internal'しかありません。 – hotkey

+0

それで彼は私が想定している 'internal'を使うべきです... – alirabiee

+0

私は' internal'がこれを行う正しい方法だとは思わないし、どちらもJavaのようなパッケージプライベートアクセスではありません。そのため、フィールドの可視性ニーズに応じてパッケージを構成するか、さらに悪いことにモジュール構造を整理する必要があるためです。これは私にはハックのように思えるでしょう... –

関連する問題