Храните команды с парой redo/undo и два стека истории. Новое действие очищает redo-историю, а отмена и повтор перемещают команду между стеками.
Разработать универсальный механизм отмены и возврата действий
Храните команды с парой redo/undo и два стека истории. Новое действие очищает redo-историю, а отмена и повтор перемещают команду между стеками.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Во многих приложениях, таких как текстовые и графические редакторы, реализуется возможность откатывать последнее действие и повторно его выполнять (Undo/Redo). Требуется написать компонент, который будет легко интегрироваться в разные типы редакторов, предоставляя единый интерфейс для управления историей изменений.
Ответ
Храните команды с парой redo/undo и два стека истории. Новое действие очищает redo-историю, а отмена и повтор перемещают команду между стеками.
Минимальный компонент для синхронных невыбрасывающих действий:
@MainActor
final class History {
struct Command {
let redo: () -> Void
let undo: () -> Void
}
private var past: [Command] = []
private var future: [Command] = []
func perform(_ command: Command) {
command.redo()
past.append(command)
future.removeAll()
}
func undo() {
guard let command = past.popLast() else { return }
command.undo()
future.append(command)
}
func redo() {
guard let command = future.popLast() else { return }
command.redo()
past.append(command)
}
}
Команда сохраняет прежние данные или обратимую операцию; редактор отвечает за правильность этих closures. Не вызывайте perform из самой команды. Для production добавьте группировку, лимит памяти и стратегию ошибок; внешние необратимые действия не превращаются в Undo автоматически.