1. Usage of the command mode
Command mode is one of the simplest and most elegant modes. A command in a pattern mode refers to an instruction that does something specific
Common application scenario: Sometimes you need to send a request to some objects, but you do not know who the recipient of the request is, and you do not know what the requested operation is. At this point, you want to design the program in a loosely coupled way so that the request sender and the request receiver can decouple from each other
Command objects have a longer lifetime than procedural request invocations. The life cycle of the object is independent of the initial request, because the request is encapsulated in the methods of the Command object and becomes the behavior of the object. This method can be called at any time the program is running.
The command mode also supports undo and queue operations
2. Example — menu program
The theme of design patterns is always to separate the immutable from the changing, and command patterns are no exception.
Simulation of traditional object-oriented language command pattern implementation
<body>
<button id="button1">Click button 1</button>
<button id="button2">Click button 2</button>
<button id="button3">Click button 3</button>
</body>
<script>
var button1 = document.getElementById('button1'),
var button2 = document.getElementById('button2'),
var button3 = document.getElementById('button3'),
// Define the setCommand function, which installs the command on the button. The execution of the command is specified by calling the execute() method of the command object.
var setCommand = function(button, command) {
button.onclick = function(){ command.execute(); }}var MenuBar = {
refresh: function(){
console.log('Refresh menu directory')}}var SubMenu = {
add: function(){
console.log('Add submenu')},del: function(){
console.log('Delete submenu')}}// Encapsulate these actions in a command class
var RefreshMenuBarCommand = function(receiver) {
this.receiver = receiver
}
RefreshMenuBarCommand.prototype.execute = function(){
this.receiver.refresh();
}
var AddSubMenuCommand = function(receiver) {
this.receiver = receiver
}
AddSubMenuCommand.prototype.execute = function(){
this.receiver.add();
}
var DelSubMenuCommand = function(receiver) {
this.receiver = receiver
}
DelSubMenuCommand.prototype.execute = function(){
this.receiver.del();
}
// Pass the command receiver into the command object and install the command object on the button
var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);
var addSubMenuCommand = new AddSubMenuCommand(SubMenu);
var delSubMenuCommand = new DelSubMenuCommand(SubMenu);
setCommand(button1, refreshMenuBarCommand);
setCommand(button2, addSubMenuCommand);
setCommand(button3, delSubMenuCommand);
</script>
Copy the code
3. Command mode in JavaScript
Implementation of command pattern in traditional object-oriented language. The pattern encapsulates procedural request invocations in the Execute method of the Command object. By encapsulating method invocations, the operation block can be wrapped into shape. The command object can be passed around, so the Client doesn’t need to care how things are going when the command is called.
The origin of the command pattern is an object-oriented substitute for the callback function.
Like the policy pattern, the command pattern has long been integrated into the JavaScript language. The block does not have to be wrapped in a command. Execute method, but can also be wrapped in a normal function. Functions, as first-class languages, can themselves be passed around. Even if we still need to request “receivers,” that’s not necessarily an object-oriented approach; closures can do the same thing
In object-oriented design, the receiver of the command pattern is stored as a property of the command object, and the command. Execute method is also called by convention to perform operations on the command. In a command-mode implementation that uses closures, the receiver is enclosed in the context in which the closure is generated, and the operation of executing the command can be simpler, simply by executing the callback function. Whether the receiver is stored as a property of the object or enclosed in the context in which the closure is generated, the receiver can be accessed when the command is executed in the future.
Closures implement command patterns:
var setCommand = function(button, func) {
button.onclick = function(){
func()
}
}
var MenuBar = {
refresh: function(){
console.log('Refresh menu interface')}}var RefreshMenuBarCommand = function(receiver){
return function(){ receiver.refresh(); }}var refreshMenuBarCommand = RefreshMenuBarCommand(MenuBar)
setCommand(button1, refreshMenuBarCommand)
Copy the code
You want to make it more clear that you are currently using the command pattern, or that you might want to provide actions such as undo commands in the future in addition to executing commands. It is best to call the execute method instead of executing the function
var RefreshMenuBarCommand = function(receiver){
return {
execute: function(){ receiver.refresh(); }}}var setCommand = function(button, command) {
button.onclick = function(){
command.execute()
}
}
var refreshMenuBarCommand = RefreshMenuBarCommand(MenuBar)
setCommand(button1, refreshMenuBarCommand)
Copy the code
4. Cancel the command
Command mode not only encapsulates the operation block, but also easily adds undo operations to the command object.
The implementation of the undo operation is generally to add a method named unexecute or undo to the command object, and perform the execute direction operation in this method.
5. Undo and redo
The best way to do a redo is to clear and then re-execute all the commands you just executed, which can also be done with a history list stack.
6. Command queue
The advantage of encapsulating requests as command objects: The life cycle of an object is almost permanent unless we actively reclaim it. That is, the life cycle of a command object is independent of when the initial request occurs. The Execute method of a command object can be executed at any time the program is running
7. Macros
A macro command is a set of commands. You can execute a batch of commands at a time by executing macro commands.
var closeDoorCommand = {
execute: function(){
console.lgo('shut down')}}var openPcCommand = {
execute: function(){
console.lgo('Turn on the computer')}}var openQQCommand = {
execute: function(){
console.lgo('login QQ')}}var MacroCommand = function(){
return {
commandsList: [].add: function(command){
this.commandsList.push(command)
},
execute: function(){
for(var i=0, command; command=this.commandsList[i++];) { command.execute(); }}}}var macroCommand = MacroCommand();
macroCommand.add(closeDoorCommand)
macroCommand.add(openPcCommand)
macroCommand.add(openQQCommand)
macroCommand.execute();
Copy the code
8. Smart commands versus dumb commands
var closeDoorCommand = {
execute: function(){
console.lgo('shut down')}}Copy the code
CloseDoorCommand does not contain any information about the receiver, which itself is responsible for executing the request, contradicting the previous command object that contains a receiver
Generally speaking, the command mode can save a receiver in the command objects to be responsible for real implementation of customer request, in this case the command object is “fool”, it is only responsible for the customer’s request to the receiver to perform, this model has the advantage of the initiator and request as much as possible to get a decoupling between the receiver.
We can also define some more “smart” command objects, “smart” command objects can directly fulfill the request, no longer need the presence of the receiver, such “smart” command objects are also called smart commands. Intelligent commands without receivers degenerate so close to the policy pattern that they are indistinguishable from the structure of the code, only from the difference in intent. The policy pattern points to a smaller problem domain, all policy objects always have the same goal, they are just different means to achieve that goal, and their internal implementation is specific to the “algorithm”. However, the intelligent command mode points to a wider problem domain, and the target solved by the command object is more divergent. The command mode can also complete functions such as undo and queuing
Unlike many other languages, JavaScript can easily implement command patterns with higher-order functions. Command mode is an invisible mode in the JavaScript language