5

Java アプリケーションのいくつかのアクションの状態の履歴を保存する必要があります。これを後でリロードして、特定のアクションで状態を復元することができます。言い換えれば、状態が関連付けられた画面があり、いつでも画面の状態を復元できるように、それと履歴の変更を保存する必要があります。これは「元に戻す」のようなものですが、2 つの状態の違いが非常に大きくなる可能性があり、状態を変更する明確に定義されたアクションがないため、厳密にはそうではありません。

例を挙げて説明しましょう。非常に基本的な画面状態には、1 つのマップのみが含まれる場合があります。状態 A では、この Map にはキー「Key1」を持つ「Object1」とキー「Key2」を持つ「Object2」への参照が含まれています。状態 B では、Map には「Object1」への参照がまだ含まれていますが、「Object2」が変更され、「Object3」が追加されています。ここで、状態 A に戻れるようにする必要があります。これには、Object3 を「ドロップ」し、Object2 を以前の状態に復元する必要があります。Object2 にどのような変更が加えられたか、Object2 のタイプさえもわからないため、カスタムの「元に戻すアクション」を定義できません。さらに、状態 A と B の Object2 の参照は同じままであるため、これらの変更は状態 A に反映され、Object2 は以前と同じではありません。

クローン メソッドを実装することが最善の解決策であると認識していますが、すべてのタイプのオブジェクト (プリミティブと標準コレクションを含む) をサポートする必要があるため、これは実現不可能です。状態遷移が発生するとすぐに Map をシリアル化し、再び必要になったときにそれを逆シリアル化する、シリアライズ可能なものを使用することを考えましたが、非常に醜い解決策のようです。

他のアイデアはありますか?ありがとう、リストレット

4

7 に答える 7

15

Memento Design Patternを調べてみましたか? あなたの問題に対して特によく定義されているようです。ウィキペディアから:

memento パターンは、オブジェクトを以前の状態に復元する (ロールバックによる元に戻す) 機能を提供するソフトウェア設計パターンです。

これはJavaであると述べたので、同じページにはJava実装のセクションもあります。

于 2009-02-03T07:19:11.160 に答える
2

あなたはPrevaylerをチェックしたいかもしれません

于 2009-02-03T07:26:54.063 に答える
2

視点の変更を検討してください。画面の状態を構成するオブジェクトを変更する代わりに、不変の状態を使用します。これは矛盾しているように聞こえるかもしれませんが、そうではありません。

たとえば、(簡単にするために)状態が単一の文字列で構成されているとします。明らかに、文字列は不変であるため、状態を保存して変更するために文字列を複製する必要はありません。例えば:

public List<String> changeTheScreen(List<String> states) {
  return states.cons(states.head() + "x");
}

public void renderTheScreen(String currentState) {
  // TODO: draw the screen given the current state
}

上記の例のListis は、 Functional Javafj.data.Listライブラリの不変のメモリ内単一リンク リスト型です (標準ライブラリには不変リストはありません)。このメソッドは、現在の状態をリストの先頭にして、状態の履歴を取得します。新しい状態を作成し、それを新しい状態リストの先頭に置くことで、画面の状態を操作します。

これと同じ原則を、状態として使用する任意の型に適用します。状態が完全に不変オブジェクトで構成されていることを確認してください(文字列とプリミティブは既に不変です)。状態に不変オブジェクトを使用すると、不変オブジェクトを複製せずに再利用できるため、今後のメンテナンスの頭痛の種を大幅に削減でき、メモリを節約できます。

不変オブジェクトはそのコンストラクターで初期化され、その内部フィールドはすべてfinal.

Functional Java には、TreeMap と呼ばれる不変のマップがあります。次のように使用します。

public List<TreeMap<String, Object>>
changeState(List<TreeMap<String, Object>> states) {
  return states.cons(states.head().set("Key1", new Object1("x")));
}
于 2009-02-03T08:37:13.390 に答える
0

必要なのが実際にマップである場合は、永続データ構造を調べることをお勧めします。たとえば、永続的なBツリー。

于 2009-02-03T07:36:48.130 に答える
0

これと似たようなことをシリアル化で行います。

アーカイブされたデータは、シリアル化された形式でファイル システムに保存されます。復元する必要があるオブジェクト グラフの部分は、メイン オブジェクトと同様にシリアル化されます。

オブジェクトのバージョンを確認し、差分が不足している/新しいフィールドに対応できることを確認してください。

ファイルシステムに保存することを選択したのは、(事実上) 無制限の容量が得られるためです。速度は私たちにとって問題ではありませんが、ファイル システム方式は驚くほど速く、ほとんどの人は余分な 50 ~ 100 ミリ秒に気づきません!

于 2009-02-03T07:15:58.937 に答える
0

シリアライゼーションはいつでも使用できます。

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
byteArrayOutputStream.close();
ByteArrayInputStream istream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream= new ObjectInputStream(istream);
Object deserialized = objectInputStream.readObject();
istream.close();

遅くて不格好ですが、機能します。

于 2009-02-03T07:17:56.170 に答える
0

私のプロジェクトでは、XML ファイルにシリアル化することで、非常によく似たものを実現しました。それは私たちにとってうまくいきました。取得したいすべてのオブジェクト - 適切に定義された方法で XML ファイルにシリアル化して、後でいつでも XML ファイルから状態を取得できるようにします。

于 2009-02-03T09:05:40.150 に答える