Undo-redo - как бы вы организовали API?
От: Sinix  
Дата: 13.01.11 04:42
Оценка:
Представим, что нас есть коллекция, имеющая возможность отменять/повторять изменения.
Чтобы не усложнять, ограничимся линейной 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);
    }


Если есть идеи, как организовать это дело покрасивше/попонятней — вэлкам!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.