Undo/Redo¶
単純な Memorable オブジェクト¶
例によってLINQPadで動作を確認しつつ進めます。 LINQPadを起動し、下記の設定をします。
- 参照設定に MoNo.dll, MoNo.Basics.dll を追加
- namespace に MoNo を追加
- Language を F# Expression に設定
次のコードを実行してみましょう。
// ActiveHistory を設定します
Core.History.ActiveHistory <- Core.History()
// Undo/Redo 可能なオブジェクト(整数値)を生成し、Historyの管理下に置きます
let a = CoreUT.Memorable 1
a.AddRef() // 参照カウンタをインクリメント → Undo/Redo対象となる
a.Value.Dump() // 1 と出力される
// 値を 2 に変更しコミットします
a.Value <- 2
Core.History.CommitActiveHistory() |> ignore
a.Value.Dump() // 2 と出力される
// Undo します(値が 1 に戻ります)
Core.History.UndoActiveHistory() |> ignore
a.Value.Dump() // 1 と出力される
// Redo します(再び値が 2 に設定されます)
Core.History.RedoActiveHistory() |> ignore
a.Value.Dump() // 2 と出力される
これが最もシンプルな Undo/Redo のサンプルコードです。
IMemorable
インターフェイス¶
Undo/Redo の対象となるオブジェクトは、下記の IMemorable
インターフェイスを実装しています。(C#)
// オブジェクトを Undo/Redo に対応するためにはこのインターフェイスを実装する必要があります。
public interface IMemorable
{
void AddRef(); // ヒストリからの参照カウントをインクリメントします。
void Release(); // ヒストリからの参照カウントをデクリメントします。
}
public interface IMemorable<T> : IMemorable
{
T Value { get; set; } // 保持している値。変更履歴の Undo/Redo が可能です。
}
冒頭のサンプルコードで用いた CoreUT.Memorable
関数は、入力された値を IMemorable<'T>
オブジェクトに包んで返す関数です。
AddRef / Release
はヒストリからの参照カウントをインクリメント/デクリメントする関数です。
この設計は、ある一つのオブジェクト(Aとします)が複数のオブジェクト(B,Cとします)から共有して参照されているケースで役に立ちます。
BやCがヒストリ管理下に入れられたときは、それらが参照するAもヒストリ管理下に入れる必要があります。
次にBのみがヒストリ管理下から外されたとき、Aは依然としてCを経由してヒストリ管理下に残らなければなりません。
このような管理を行うために参照カウンタが必要となります。