Digiguru.co.uk

The command pattern - invoker object

18 Mar 2015

Reading time: 1 minute

When dealing with the command pattern, we have to identify an invoker object.

This object will process our concrete commands and store a list of events that have been applied. What does this invoker object look like. I identified the following interface. Firstly we know we want the ability to “undo” and “redo”.

this.UndoActions = [];
this.RedoActions = [];
this.Undo = function Undo(callback) {
    var action = this.UndoActions.pop();
    this.RedoActions.push(action.Opposite());
    return action.Run();
};
this.Redo = function Redo(callback) {
    var action = this.RedoActions.pop();
    this.UndoActions.push(action.Opposite());
    return action.Run();
};

This is fairly straight forward. We store a list of undo actions, and redo actions. Every time you perform an Undo action, you need to record the opposite action in the Redo list, and then perform the action, the finally return a promise. (for those who like to pass in a callback, you can also do this as an optional parameter).

Okay - so given this, what does the action object look like? These are the concerete commands, so need to be assigned for each different command you have.

For all of the concrete commands you need a core object.

this.reverse = false;
this.Run = function(callback) {
    if(reverse) {
        return this.forward(callback);
    } else {
        return this.backward(callback);
    }
};
this.Opposite = function () {
    reverse = !reverse;
};

But you need to also add the following functions to each concrete command. Here is an example for “moveTable”.

this.forward = function (callback) {
    var table = getTable(args.table);
    console.log("MoveTable", args);
    return table.animateTable(args.current, callback); 
};
this.backward = function (callback) {
    var table = getTable(args.table);
    console.log("UndoMoveTable", args);
    return table.animateTable(args.previous, callback);
};

This ends the description of the Undo / Redo functionality. In a later post we will put it all together and try creating some fully functional examples.