4

この質問のタイトルをどのように達成できるかについて、すでにいくつかの調査を行っています。私が取り組んでいるアプリは、数年ほど開発されています (ただし、進行は遅いですが、現実の世界での様子はご存知のとおりです)。現在、複数レベルの取り消し/やり直し機能を組み込むことが必須になっています。「始める前にこれについて考えるべきだった」と言うのは少し遅いです...まあ、私たちはそれについて考えていました-そして私たちはそれについて何もしませんでしたが、今ここにあります. SO(および外部リンク)を検索すると、最も一般的な2つの方法が次のように見えることがわかります...

コマンドパターン

記念品のパターン

コマンド パターンは非常に多くの作業が必要なように見えます。その過程で何千ものバグが発生することしか想像できないので、あまり好きではありません。

Memento のパターンは、実際、私が頭の中で考えていたものとよく似ています。現在メモリ内にあるオブジェクト モデルのスナップショットをすばやく取得する方法があれば、それをどこかに保存できると考えていました (メモリ内、ファイル内など)。素晴らしいアイデアのように思えますが、これについて私が見ることができる唯一の問題は、それが私たちがすでに書いたものとどのように統合されるかということです. 大きなパネル (場合によっては数百) に画像を描画し、ユーザーが UI またはカスタム ビルドのプロパティ グリッドを介してそれらを操作できるように、アプリが表示されます。アプリ全体が大きなオブザーバー パターンでリンクされています。2 番目に何かが変更されると、イベントが発生し、更新が必要なすべての処理が行われます。これは素晴らしいことですが、ユーザーがプロパティ グリッドの texfield にテキストを入力している場合、UI が追いつくまでに少し時間がかかると考えずにはいられません (ユーザーがキーを押すたびに、新しいスナップショットが追加されるようです)元に戻すリストへ)。だからあなたへの私の質問は....

  • Memento パターンに代わる、うまくいくかもしれない何か良い方法を知っていますか?
  • Memento パターンがここに収まると思いますか、それともアプリの速度が遅くなりすぎると思いますか。
  • Mementoパターンが進むべき道である場合、オブジェクトモデルのスナップショットを作成する最も効率的な方法は何ですか(私はそれをシリアル化するか何かを考えていました)
  • スナップショットをメモリに保存する必要がありますか、それともファイルに保存できますか?

ここまで読んでくれてありがとう。皆様からのご意見は貴重であり、非常に高く評価されます。

4

4 に答える 4

5

さて、これがこの問題に関する私の考えです。

1- マルチレベルの取り消し/やり直し機能が必要です。そのため、スタックに保存できる、実行されたユーザー アクションを保存する必要があります。

2-メメントパターンを通して考えられる操作によって何が変更されたかを特定する方法の2番目の問題は、かなりの課題です。Memento は、メモリ内のオブジェクトの初期状態を保持することがすべてです。

どちらの場合も、操作によって変更された内容を保存して、この情報を使用して操作を元に戻すことができるようにする必要があります。

コマンド パターンは元に戻す/やり直し機能用に設計されており、数年にわたって使用され、ほとんどのアプリケーションで機能する設計を実装するのは遅いですが、その価値があると言えます。

于 2010-12-02T17:59:14.367 に答える
3

パフォーマンスが許せば、各アクションの前にドメインをシリアル化できます。オブジェクト自体が大きくない場合、数百のオブジェクトは多くありません。

オブジェクト グラフはおそらく自明ではない (つまり、継承、サイクルなどを使用する) ため、統合された XmlSerializer と JsonSerializers は論外です。Json.net はこれらをサポートしていますが、一部の型 (ローカルの DateTime、数値など) でいくつかの不可逆変換を行うため、これも問題です。

protobuf シリアライザーには、なんらかの形式の DTD (.proto ファイル) か、名前を数値にマッピングする属性を使用してすべてのプロパティを装飾する必要があるため、最適ではない可能性があります。

BinaryFormatter はほとんどのものをシリアル化できます。すべてのクラスを [Serializable] 属性で装飾するだけです。ただ、自分では使っていないので、わからないところがあるかもしれません。おそらくシングルトンまたはイベントに関連しています。

于 2010-12-02T18:55:35.703 に答える
1

MonitoredUndoFrameworkが役立つ場合があります。http://muf.codeplex.com/

変更が発生したときにそれを監視することで、mementoパターンに似たものを使用し、変更を元に戻す/やり直すデリゲートを元にスタックに配置できるようにします。

ドキュメントをシリアル化/逆シリアル化するアプローチを検討しましたが、オーバーヘッドが心配でした。代わりに、プロパティベースごとにプロパティのモデル(またはビューモデル)の変更を監視します。次に、必要に応じて、MUFライブラリを使用して関連する変更を「バッチ処理」し、変更の単位として元に戻す/やり直すようにします。

基になるモデルの変更に対応するためのUIセットアップがあるという事実は良いことです。そこに元に戻る/やり直しロジックを挿入すると、変更がUIに反映されるようです。

ラグやパフォーマンスの低下はあまり見られないと思います。モデル内のデータに基づいてレンダリングする図を使用した、同様のアプリケーションがあります。これまでのところ、これで良い結果が得られています。

詳細とドキュメントは、codeplexサイト(http://muf.codeplex.com/ )にあります。このライブラリは、.NET 3.5、4.0、SL4、およびWP7をサポートするNuGetからも利用できます。

于 2011-06-21T03:24:00.870 に答える
1

元に戻す/やり直しの重要な点は次のとおりです。

  • 保存して復元する必要がある状態を知る
  • いつ状態を保存する必要があるかを知る

事後に元に戻す/やり直しを追加するのは、常に面倒なことです - (このコメントがあなたにとって役に立たないことはわかっていますが、始める前にアプリケーションフレームワークにサポートを設計することが常に最善です.開発中の友好的なパターン)。

おそらく最も単純なアプローチは、記念品ベースのアプローチです。

  • 「ドキュメント」を構成するすべてのデータを見つけます。このデータを何らかの方法で統合して、一貫した全体を形成することはできますか? 通常、ドキュメント構造をファイルにシリアル化できる場合、必要なロジックはシリアル化システムにあるため、これを直接使用することの欠点は、通常、すべてをシリアル化して元に戻す必要があることです。巨大で遅くなります。可能であれば、コードをリファクタリングして、(a) アプリケーション全体で使用される共通のシリアライゼーション インターフェイスが存在するようにし (データのすべての部分をジェネリック コールを使用して保存/復元できるようにします)、(b) すべてのサブシステムをカプセル化します。そのため、データへの変更は共通のインターフェースを経由する必要があります (多くの人がメンバー変数を直接変更するのではなく、それらはすべて、オブジェクトによって提供される API を呼び出して、それ自体に変更を加えるように要求する必要があります)。(c) データのすべてのサブ部分は「バージョン番号」を保持します。((b) のインターフェイスを介して) 変更が行われるたびに、そのバージョン番号をインクリメントする必要があります。このアプローチは、ドキュメント全体をスキャンし、バージョン番号を使用して、最後に見た後に変更された部分だけを見つけ、最小限の量をシリアル化して、変更された状態を保存および復元できることを意味します。

    • 単一の元に戻すステップを記録できるメカニズムを提供します。これは、複数のシステムがデータ構造に変更を加えることができるようにし、すべてが更新されたときに元に戻す記録をトリガーすることを意味します。これをいつ実行するかを判断するのは難しいかもしれませんが、UI が各入力イベントの処理を終了したときに、メッセージ ループ内の変更 (上記を参照) についてドキュメントをスキャンすることで通常は達成できます。

それを超えて、元に戻す/やり直し以外にも多くの利点があるため、コマンドベースのアプローチを使用することをお勧めします。

于 2010-12-02T19:48:57.490 に答える