Отменить функциональность в дизайне MVC - PullRequest
0 голосов
/ 17 апреля 2011

У меня есть приложение C ++, разработанное в соответствии с классическим Model-View-Controller pattern . Модель модифицируется через интерфейс контроллера внешним источником с помощью шаблона команды . Команды представлены объектом Action (и его производными).

Теперь я хочу иметь возможность отменить изменения, но моя проблема в том, что в моем контроллере нет геттеров, только сеттеры. Это кажется вполне логичным, поскольку нет причин, по которым кто-то должен иметь возможность получать информацию о модели через контроллер. Таким образом, мои объекты Action не могут хранить состояние модели, поскольку они не имеют к ней доступа.

Как бы это решить? Я бы хотел, чтобы мое приложение было максимально расширяемым , и я не совсем уверен, какой вариант лучше для этого подходит. Методы, которые я до сих пор до сих пор:

  1. Установка методов получения в контроллере. Похоже, это идет вразрез с паттерном MVC.
  2. Задание для Движения указателя на Вид. Действие может затем либо:
    1. Используйте отдельные геттеры, чтобы получить состояние определенных элементов модели, которую нужно изменить.
    2. Используйте метод Memento , реализованный в Viewer.

Может быть, есть еще лучший способ сделать это? Прямо сейчас, чтобы быть лучшим вариантом, кажется, 2, подопция 1 (с подопцией 2, я вполне мог бы сохранить намного больше состояния, чем необходимо, чтобы отменить одно действие).

Примечание: Я знаю, что есть другие вопросы о том, как выполнить действие отмены. Тем не менее, единственные ответы, которые я нашел, содержали предложения использовать шаблон Command или Memento. Я знаю, что это наиболее вероятный путь. Я спрашиваю о том, как интегрировать это как можно более четко и расширяемо в дизайн MVC.

[Редактировать] Что мне не нравится в паттерне Memento, так это то, что он заставляет меня сохранять полное состояние. Допустим, моя модель представляет собой матрицу 1000x1000, а моя команда - ChangeOneValueAtLocation. Чтобы иметь возможность отменить свои изменения, объекту ChangeOneValueAtLocation нужно только сохранить предыдущее значение местоположения, которое он меняет, но это не представляется возможным с Memento. Чем больше моя модель, тем больше эта проблема.

[Редактировать 2] Еще одна проблема, с которой я столкнулся в Memento в конкретном случае этого приложения: для каждого метода объект Command может выполняться в модели, есть метод, который делает прямо противоположное (или может легко уговаривать сделать это). Вот почему я считаю ненужным хранить все состояние, в этом не должно быть необходимости, возвращать одну команду очень просто, единственная проблема - получить данные, чтобы это можно было сделать.

Кроме того, мне не нужно иметь возможность отменить определенную Команду, только самую верхнюю в моем стеке истории.

Ответы [ 3 ]

2 голосов
/ 17 апреля 2011

Я бы действительно порекомендовал встроить дерево отмены в свой контроллер.

. Встраивание его в модель может привести к неприятностям:

  • "модель", как правило, фрагментирована для каждого вида(у каждого представления есть своя частичная модель)
  • это приведет к неатомарному откату (отмена части операции из-за того, что представление не знает, какие другие вещи (модели) могут понадобитьсябыть отмененным и т. д.)

Контроллер является «диспетчером действий», поэтому он должен сказать

  1. состояние клонирования (все модели) снимок
  2. добавьте действие в историю со ссылкой на снимок
  3. запустите действие

, тогда отмена будет

  1. всплывающее действие из стека истории (опционально нажмите «будущее»'stack)
  2. восстановить снимок
  3. представление экрана

Кроме того, отменить работу с высокоуровневыми действиями (см. Composite Pattern или Command Pattern)

2 голосов
/ 18 апреля 2011

Я также поддерживаю слой модели, содержащий поддержку отмены.Есть немало способов справиться с этим на стороне модели.Первое и наиболее очевидное - это то, что сами модели запоминают историю изменений с помощью «меток», но, вероятно, будет сложно синхронизировать все классы моделей.

Еще один вариант - создать историюМенеджер, имеющий концепцию «транзакции», которая заставляет его генерировать точку отмены и делать снимок ваших моделей, или начинать запись изменений (для уменьшения использования памяти), или записывать команды, которые вызывают изменения модели и т. д.Модели уведомляют менеджера об изменении, и, наконец, вы завершаете транзакцию (или нет, потому что следующий запуск транзакции может быть концом предыдущей).Как только вы добавите возможность отката до определенного момента, работа будет выполнена.Сделав вещи немного более сложными в этом классе менеджера, вы можете создать дерево отмены (как в emacs), так что это также довольно гибкий способ приблизиться к нему.

Приведенное выше решение не совсем вслой модели, хотя.Это класс поддержки, управляемый как моделью, так и контроллером.Если вы удалите концепцию транзакции, то она будет полностью управляема моделью, но реализация концепции операции отмены может быть несколько хитрой.Если вы измените его, чтобы он действовал как командный прокси, это будет единственная сущность, используемая вашими контроллерами, и, очевидно, это модель.На данный момент слишком грубый дизайн, чтобы выбирать один подход из другого, но я склоняюсь к модели «транзакции».Это достаточно легко реализовать.

0 голосов
/ 17 апреля 2011

Создание функции отмены в самой модели.Позвольте вашей модели вести список команд.Запускайте команды в обратном порядке, когда ваше представление передает сигнал отмены модели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...