Требования к решению
Механизм undo-redo, который мы намереваемся обеспечить, должен удовлетворять следующим свойствам:
· U1 Механизм должен быть применим к широкому классу интерактивных приложений независимо от их проблемной области.
· U2 Механизм не должен требовать перепроектирования при добавлении новых команд.
· U3 Он должен разумно использовать ресурсы памяти.
· U4 Он должен быть применимым к откатам как на один, так и несколько уровней.
Первое требование следует из того, что ничего проблемно-специфического в откатах и повторах нет. Только для облегчения обсуждения мы будем использовать в качестве примера знакомый каждому инструмент - текстовый редактор, (подобный Notepad или Vi), позволяющий пользователям вводить тексты и выполнять такие команды, как: INSERT_LINE, DELETE_LINE,GLOBAL_REPLACEMENT (одного слова в тексте другим) и другие. Но это только пример, и ни одна из концепций, обсуждаемых ниже, не является характерной только для текстовых редакторов.
Второе требование означает, что Undo и Redo имеют особый статус и не могут рассматриваться подобно любым другим командам интерактивной системы. Будь Undo обычной командой, ее структура требовала бы разбора случаев в форме:
If "Последняя команда была INSERT_LINE" then "Undo эффект INSERT_LINE"elseif "Последняя команда была DELETE_LINE" then "Undo эффект DELETE_LINE"и т.д.Мы знаем (см. лекцию 3 курса "Основы объектно-ориентированного программирования"), как плохи такие структуры, противоречащие принципу Единственного Выбора и затрудняющие расширяемость системы. Пришлось бы изменять программный текст при всяком добавлении новой команды. Хуже того, код каждой ветви отражал бы код соответствующей команды, например, первая ветвь должна бы знать достаточно много о том, что делает команда INSERT_LINE. Это было бы свидетельством изъянов проекта.
Третье требование заставляет нас бережно относиться к памяти. Понятно, что механизм undo-redo требует хранения некоторойинформации для каждой команды Undo: например, при выполнении DELETE_LINE, нет возможности выполнить откат, если перед выполнением команды не запомнить где-нибудь удаляемую строку и ее позицию в тексте. Но следует хранить только то, что логически необходимо.
Вследствие третьего требования исключается такое очевидное решение, как сохранение полного состояния системы перед выполнением каждой команды. Такое решение можно было бы тривиально написать, используя свойства STORABLE (см.лекцию 8курса "Основы объектно-ориентированного программирования"), но оно было бы нереалистичным, так как просто пожирало бы память. Нужно придумать что-то более разумное.
Последнее требование поддержки произвольного числа уровней отката уже обсуждалось. В данном случае оказывается проще рассмотреть откат на один уровень и затем обобщить решение на произвольное число уровней.
Этими требованиями заканчивается презентация проблемы. Хорошей идеей, как обычно, является попытка самостоятельного поиска решения, прежде чем продолжить чтение этой лекции.