Design Patterns in Javascript Part 5

Posted By : Rudhishthir Prakash | 01-Oct-2018
The Command Pattern
 
The goal of the command pattern is to encapsulate in action within an object and this kind of goes against the grain of object-oriented programming because object-oriented programming revolves around the object and object is typically a noun, which means it is a person, or a place or a thing. And the command pattern seeks to use an object as a verb.
But the idea behind the command pattern is sound it gives us the ability to separate the responsibility of issuing a command from anything that is executing the command. In this separation allows us to write a clean and flexible API.
 
For example, 
function Calculator(){
	this._currentValue = 0;
}

Calculator.prototype = {
	add: function(value){
		this._currentValue += value; 
	},
	subtract: function(value){
		this._currentValue -= value; 
	},
	getCurrentValue: function(){
		return this._currentValue;
	}
};
It would be much more simple if we would have just one method execute and it would simply execute a command. And the command would represent an addition, subtraction or so on or so forth.

Calculator.prototype = {
	execute: function(){
		this._currentValue = command.execute(this._currentValue);
	},
	getCurrentValue: function(){
		return this._currentValue;
	}
};

function Command(fn, value){
	this.execute = fn;
	this.value = value;
}

function AddCommand(value){
	Command.call(this, function(value){
		return value + this.value;
	}, value);
}

function SubCommand(value){
	Command.call(this, function(value){
		return value - this.value;
	}, value);
}
var calc = new Calculator();
calc.execute(new AddCommand(19));
console.log(calc.getCurrentValue()); //19
calc.execute(new AddCommand(1));
console.log(calc.getCurrentValue()); //20
calc.execute(new AddCommand(19)); //39
calc.execute(new SubCommand(4));
console.log(calc.getCurrentValue()); //35
Now that our actions are encapsulated by objects, we can actually do something with those objects. We can keep track of them and we can do an undo feature to our calculator.
function Calculator(){
	this._currentValue = 0;
	this.commands = [];
}

Calculator.prototype = {
	execute: function(){
		this._currentValue = command.execute(this._currentValue);
		this.commands.push(command);
	},
	undo: function(){
		var cmd = this.commands.pop();
		this._currentValue = cmd.undo(this._currentValue);
	},
	getCurrentValue: function(){
		return this._currentValue;
	}
};

function Command(fn, undo, value){
	this.execute = fn;
	this.value = value;
	this.undo = undo;
}

function add(value){
	return value + this.value;
}

function sub(value){
	return value - this.value;
}

function AddCommand(value){
	Command.call(this, add, sub, value);
}

function SubCommand(value){
	Command.call(this, sub, add, value);
}
var calc = new Calculator();
calc.execute(new AddCommand(19));
console.log(calc.getCurrentValue()); //19
calc.undo();
console.log(calc.getCurrentValue()); //0
So, by using the command pattern, we were able to separate the issuing of the command from executing of the command, which gave us a lot of flexibility because then we can add more functionality to our calculator by simply adding new command types. But that is not all, because we were encapsulating in action within object we actually had something we could work with which once again allowed us to add more functionality to our application.
Use Case: One can use a command pattern to decouple the parsing of byte stream when implementing a protocol from the action associated to the message. The channel constructs the right command object upon receiving some byte from the wire e.g. using the abstract factory pattern and is put into the queue to be executed later or in another thread.

About Author

Author Image
Rudhishthir Prakash

Rudhishthir is a technical enthusiast having experience in C#.NET, NodeJS & various front-end technologies. He has great experience in building quality applications with innovative ideas. He also has proven expertise in handling clients.

Request for Proposal

Name is required

Comment is required

Sending message..