Command pattern — это поведенческий шаблон проектирования, который инкапсулирует запрос как объект, позволяя параметризовать клиентов с разными запросами, ставить запросы в очередь и поддерживать отмену операций. В контексте Backbone.js этот подход особенно полезен для управления действиями пользователя, упрощения логики undo/redo и централизованного контроля событий интерфейса.
В Backbone.js взаимодействие пользователя с приложением обычно происходит через события в View, которые изменяют состояние Model. Command pattern добавляет промежуточный уровень, где каждая операция пользователя оформляется как отдельный объект команды. Такой объект содержит:
Это позволяет:
Простейшая структура команды в Backbone.js выглядит следующим образом:
var Command = Backbone.Model.extend({
execute: function() {
throw new Error('execute() должен быть реализован');
},
undo: function() {
throw new Error('undo() должен быть реализован');
}
});
Конкретные команды наследуют эту базовую модель и реализуют методы execute и undo. Например, команда изменения атрибута модели:
var ChangeAttributeCommand = Command.extend({
initialize: function(options) {
this.model = options.model;
this.attr = options.attr;
this.newValue = options.newValue;
this.oldValue = this.model.get(this.attr);
},
execute: function() {
this.model.set(this.attr, this.newValue);
},
undo: function() {
this.model.set(this.attr, this.oldValue);
}
});
Для управления командами удобно использовать CommandManager, который хранит историю и предоставляет методы для выполнения, отмены и повтора команд:
var CommandManager = Backbone.Model.extend({
initialize: function() {
this.history = [];
this.redoStack = [];
},
executeCommand: function(command) {
command.execute();
this.history.push(command);
this.redoStack = [];
},
undo: function() {
var command = this.history.pop();
if (command) {
command.undo();
this.redoStack.push(command);
}
},
redo: function() {
var command = this.redoStack.pop();
if (command) {
command.execute();
this.history.push(command);
}
}
});
Этот подход позволяет централизованно контролировать действия пользователя и гарантирует, что любая операция может быть отменена или повторена без дублирования логики.
В Backbone.js события интерфейса удобно связывать с командами через View. Пример:
var ItemView = Backbone.View.extend({
events: {
'click .edit': 'editItem',
'click .undo': 'undoAction',
'click .redo': 'redoAction'
},
initialize: function(options) {
this.commandManager = options.commandManager;
},
editItem: function() {
var command = new ChangeAttributeCommand({
model: this.model,
attr: 'name',
newValue: 'Новое имя'
});
this.commandManager.executeCommand(command);
},
undoAction: function() {
this.commandManager.undo();
},
redoAction: function() {
this.commandManager.redo();
}
});
Backbone предоставляет легковесную архитектуру, где Model, View и Collection взаимодействуют через события. Использование Command pattern вписывается естественно:
Такое разделение делает код более структурированным, уменьшает связанность и упрощает поддержку крупных приложений с множеством интерактивных действий пользователя.