97 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			97 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								---
							 | 
						||
| 
								 | 
							
								title: Command pattern
							 | 
						||
| 
								 | 
							
								categories:
							 | 
						||
| 
								 | 
							
								  - DSA
							 | 
						||
| 
								 | 
							
								tags:
							 | 
						||
| 
								 | 
							
								  - design-patterns
							 | 
						||
| 
								 | 
							
								---
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# 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:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```jsx
							 | 
						||
| 
								 | 
							
								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:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```jsx
							 | 
						||
| 
								 | 
							
								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:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```jsx
							 | 
						||
| 
								 | 
							
								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:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```jsx
							 | 
						||
| 
								 | 
							
								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;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```jsx
							 | 
						||
| 
								 | 
							
								calculator.execute(new AddCommand(100));
							 | 
						||
| 
								 | 
							
								calculator.execute(new SubCommand(24));
							 | 
						||
| 
								 | 
							
								calculator.execute(new MulCommand(6));
							 | 
						||
| 
								 | 
							
								calculator.execute(new DivCommand(2));
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Or undo them with:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```jsx
							 | 
						||
| 
								 | 
							
								calculator.undo();
							 | 
						||
| 
								 | 
							
								```
							 |