Command pattern
This is typically used when you want to sequence a fairly large number of actions in a series with the option to undo or reverse them. Similarly to the mediator it has a one-to-many architecture (there is a central class that sequences the commands which are handled by other classes) but in addition to sending and routing requests between colleagues, it keeps a central store of them and can reverse actions.
The typical example is a calculator. Will will generate this using constructor function syntax, rather than ES6 class syntax.
You have a bunch of arithmetic functions:
function add(x, y) {
return x + y;
}
function sub(x, y) {
return x - y;
}
function mul(x, y) {
return x * y;
}
function div(x, y) {
return x / y;
}
Then a generalised Command
class that has three parameters: undo, execute, and return a value:
var Command = function (execute, undo, value) {
this.execute = execute;
this.undo = undo;
this.value = value;
};
We then create the specific commands by combining the functions and the Command
class:
var AddCommand = function (value) {
return new Command(add, sub, value);
};
// We would create one of these classes for each of the four operations
So now the add
and subtract
functions slot into execute
and undo
on the Command
class.
Finally we create the centralised command class that will return values based on the individual commands it sequences and issues, store them and remove them:
var Calculator = function () {
var current = 0;
var commands = [];
function action(command) {
var name = command.execute.toString().substr(9, 3);
return name.charAt(0).toUpperCase() + name.slice(1);
}
return {
execute: function (command) {
current = command.execute(current, command.value);
commands.push(command);
log.add(action(command) + ": " + command.value);
},
undo: function () {
var command = commands.pop();
current = command.undo(current, command.value);
log.add("Undo " + action(command) + ": " + command.value);
},
getCurrentValue: function () {
return current;
}
}
calculator.execute(new AddCommand(100));
calculator.execute(new SubCommand(24));
calculator.execute(new MulCommand(6));
calculator.execute(new DivCommand(2));
Or undo them with:
calculator.undo();