私の意見では、UNDO / REDOは2つの方法で広く実装できます。1.コマンドレベル(コマンドレベルの取り消し/やり直しと呼ばれる)2.ドキュメントレベル(グローバルの取り消し/やり直しと呼ばれる)
コマンドレベル:多くの回答が指摘するように、これはMementoパターンを使用して効率的に達成されます。コマンドがアクションのジャーナル化もサポートしている場合、やり直しは簡単にサポートされます。
制限:コマンドのスコープがなくなると、元に戻す/やり直しは不可能になり、ドキュメントレベル(グローバル)の元に戻す/やり直しが発生します。
大量のメモリ空間を必要とするモデルに適しているため、あなたのケースはグローバルの元に戻す/やり直しに当てはまると思います。また、これは選択的に元に戻す/やり直しにも適しています。2つのプリミティブタイプがあります。
- 全メモリの取り消し/やり直し
- オブジェクトレベルのやり直し
「すべてのメモリの元に戻す/やり直し」では、メモリ全体が接続されたデータ(ツリー、リスト、グラフなど)として扱われ、メモリはOSではなくアプリケーションによって管理されます。したがって、C ++の場合、新しい演算子と削除演算子は、aなどの操作を効果的に実装するためのより具体的な構造を含むようにオーバーロードされます。ノードが変更された場合は、b。データの保持やクリアなどの機能は、基本的にメモリ全体をコピーし(メモリ割り当てがすでに高度なアルゴリズムを使用してアプリケーションによって最適化および管理されている場合)、それをスタックに格納することです。メモリのコピーが要求された場合、ツリー構造は、浅いコピーまたは深いコピーを持つ必要性に基づいてコピーされます。ディープコピーは、変更された変数に対してのみ作成されます。すべての変数はカスタム割り当てを使用して割り当てられるため、アプリケーションには、必要に応じていつ削除するかという最終決定権があります。一連の操作をプログラムで選択的に元に戻す/やり直す必要がある場合に、元に戻す/やり直しを分割する必要がある場合は、非常に興味深いことが起こります。この場合、それらの新しい変数、または削除された変数または変更された変数にのみフラグが付けられるため、元に戻す/やり直しはそれらのメモリのみを元に戻す/やり直します。そのような場合、「ビジターパターン」の新しいアイデアが使用されます。「オブジェクトレベルの元に戻す/やり直し」と呼ばれます 削除された変数または変更された変数にはフラグが付けられ、元に戻す/やり直しはそれらのメモリのみを元に戻す/やり直します。そのような場合、「ビジターパターン」の新しいアイデアが使用されます。「オブジェクトレベルの元に戻す/やり直し」と呼ばれます 削除された変数または変更された変数にはフラグが付けられ、元に戻す/やり直しはそれらのメモリのみを元に戻す/やり直します。そのような場合、「ビジターパターン」の新しいアイデアが使用されます。「オブジェクトレベルの元に戻す/やり直し」と呼ばれます
- オブジェクトレベルの元に戻す/やり直し:元に戻す/やり直しの通知が呼び出されると、すべてのオブジェクトがストリーミング操作を実装し、ストリーマーはオブジェクトからプログラムされた古いデータ/新しいデータを取得します。乱されていないデータは乱されません。すべてのオブジェクトは引数としてストリーマーを取得し、UNDo / Redo呼び出し内で、オブジェクトのデータをストリーム/ストリーム解除します。
1と2の両方に、1。BeforeUndo()2. AfterUndo()3. BeforeRedo()4. AfterRedo()などのメソッドを含めることができます。これらのメソッドは、(コンテキストコマンドではなく)基本的な元に戻す/やり直しコマンドで公開する必要があります。これにより、すべてのオブジェクトがこれらのメソッドを実装して特定のアクションを実行できるようになります。
良い戦略は、1と2のハイブリッドを作成することです。美しさは、これらのメソッド(1&2)自体がコマンドパターンを使用することです