Представим, что нас есть коллекция, имеющая возможность отменять/повторять изменения.
Чтобы не усложнять, ограничимся линейной undo-redo моделью без параллельных состояний.
Пусть создание коллекции, запоминание состояния и операции отмены/повтора выглядит как
StateManager stateManager = new StateManager();
StatefulCollection<int> values = new StatefulCollection<int>(stateManager);
// ...
StateKey state0 = stateManager.SetCheckpoint("+0");
// ...
StateKey state1 = stateManager.SetCheckpoint("+1,2");
// ...
StateKey state2 = stateManager.SetCheckpoint("+3,1->11");
// ...
StateKey state3 = stateManager.SetCheckpoint("11->1,+4");
// ...
stateManager.CurrentState = stateManager.States[1]; // == stateManager.CurrentState = state1;
stateManager.CurrentState = state1; // == stateManager.Undo(state2);
stateManager.CurrentState = state0; // == stateManager.Undo(state1);
stateManager.CurrentState = state2; // == stateManager.Redo(state2);
stateManager.CurrentState = state3; // == stateManager.Redo(state3);
Собсно вопрос: в какой момент вы бы организовали запоминание состояния?
А) Анонсированием:
StateKey state1 = stateManager.SetCheckpoint("+1,2");
values.Add(1);
values.Add(2);
Б) Подтверждением самого факта операции:
values.Add(1);
values.Add(2);
StateKey state1 = stateManager.SetCheckpoint("+1,2");
?
Разумеется, SetCheckpoint() надо будет обозвать так, чтобы отразить подразумеваемый способ использования.
Например, BeginChangeset() | Confirm().
На самом деле как оно будет устроено — неважно: для типовых сценариев шаманство будет обёрнуто в disposable-обёртку
StateKey state1 = null;
using (Operation op = stateManager.BeginOperation("+1,2"))
{
state1 = op.InitialState;
values.Add(1);
values.Add(2);
op.Commit();
} // == if (!commited) stateManager.CurrentState = op.InitialState;
| пример использования целиком |
| internal static void StatesAnnonce()
{
StateManager stateManager = new StateManager();
StatefulCollection<int> values = new StatefulCollection<int>(stateManager);
StateKey state0 = stateManager.SetCheckpoint("+0");
values.Add(0);
StateKey state1 = stateManager.SetCheckpoint("+1,2");
values.Add(1);
values.Add(2);
StateKey state2 = stateManager.SetCheckpoint("+3,1->11");
values.Add(3);
values[1] = 11;
StateKey state3 = stateManager.SetCheckpoint("11->1,+4");
values[1] = 1;
values.Add(4);
stateManager.CurrentState = stateManager.States[1]; // == stateManager.CurrentState = state1;
stateManager.CurrentState = state1; // == stateManager.Undo(state2);
stateManager.CurrentState = state0; // == stateManager.Undo(state1);
stateManager.CurrentState = state2; // == stateManager.Redo(state2);
stateManager.CurrentState = state3; // == stateManager.Redo(state3);
}
internal static void StatesConfirm()
{
StateManager stateManager = new StateManager();
StatefulCollection<int> values = new StatefulCollection<int>(stateManager);
values.Add(0);
StateKey state0 = stateManager.SetCheckpoint("+0");
values.Add(1);
values.Add(2);
StateKey state1 = stateManager.SetCheckpoint("+1,2");
values.Add(3);
values[1] = 11;
StateKey state2 = stateManager.SetCheckpoint("+3,1->11");
values[1] = 1;
values.Add(4);
StateKey state3 = stateManager.SetCheckpoint("11->1,+4");
stateManager.CurrentState = stateManager.States[1]; // == stateManager.CurrentState = state1;
stateManager.CurrentState = state1; // == stateManager.Undo(state2);
stateManager.CurrentState = state0; // == stateManager.Undo(state1);
stateManager.CurrentState = state2; // == stateManager.Redo(state2);
stateManager.CurrentState = state3; // == stateManager.Redo(state3);
}
internal static void StatesOperations()
{
StateManager stateManager = new StateManager();
StatefulCollection<int> values = new StatefulCollection<int>(stateManager);
StateKey state0;
StateKey state1;
StateKey state2;
StateKey state3;
using (Operation op = stateManager.BeginOperation("+0"))
{
state0 = op.InitialState;
values.Add(0);
op.Commit();
} // == if (!commited) stateManager.CurrentState = op.InitialState;
using (Operation op = stateManager.BeginOperation("+1,2"))
{
state1 = op.InitialState;
values.Add(1);
values.Add(2);
op.Commit();
} // == if (!commited) stateManager.CurrentState = op.InitialState;
using (Operation op = stateManager.BeginOperation("+3,1->11"))
{
state2 = op.InitialState;
values.Add(3);
values[1] = 11;
op.Commit();
}
using (Operation op = stateManager.BeginOperation("11->1,+4"))
{
state3 = op.InitialState;
values[1] = 1;
values.Add(4);
op.Commit();
}
stateManager.CurrentState = stateManager.States[1]; // == stateManager.CurrentState = state1;
stateManager.CurrentState = state1; // == stateManager.Undo(state2);
stateManager.CurrentState = state0; // == stateManager.Undo(state1);
stateManager.CurrentState = state2; // == stateManager.Redo(state2);
stateManager.CurrentState = state3; // == stateManager.Redo(state3);
}
|
| |
Если есть идеи, как организовать это дело покрасивше/попонятней — вэлкам!