Command mode: The request is wrapped in an object as a command and passed to the calling object. The calling object looks for a suitable object that can handle the command and passes the command to the corresponding object, which executes the command.

Life chestnut: customers place orders, orders record the products purchased by customers, and the warehouse prepares goods for customers according to orders.

Model features

The command mode consists of three roles:

  1. The publisherinvoker(issuing commands, calling command objects, not knowing how and by whom to execute);
  2. The receiverreceiver(provide the corresponding interface to process the request, do not know who initiated the request);
  3. Command objectcommand(Receives the command and invokes the receiver’s corresponding interface to process the publisher’s request).

Invoker and Receiver are independent, encapsulating the request into a command object. The command object invokes the interface corresponding to receiver and receiver to execute the request.

The command object acts as a bridge between the publisher invoker and the receiver (intermediate objects intervene). The decoupling between the publisher and the receiver is realized. Compared with the procedural request invocation, the command object command has a longer life cycle. The receiver Receiver attribute method is encapsulated in the command object command attribute, so that the receiver object Receiver can be called at any time when the program executes. Therefore, command can further control and process requests, such as delay, reservation, queuing, and cancellation.

Code implementation

class Receiver {  // Receiver class
  execute() {
    console.log('Receiver performs request'); }}class Command {   // Command object class
  constructor(receiver) {
    this.receiver = receiver;
  }
  execute () {    // The call receiver is executed on the interface
    console.log('Command Object -> Receiver -> Interface execution');
    this.receiver.execute(); }}class Invoker {   // Publisher class
  constructor(command) {
    this.command = command;
  }
  invoke() {      // Issue the request to invoke the command object
    console.log('Publisher publishes request');
    this.command.execute(); }}const warehouse = new Receiver();       / / warehouse
const order = new Command(warehouse);   / / order
const client = new Invoker(order);      / / customer
client.invoke();

/* Output: the publisher issues the request command object -> Receiver -> corresponding interface execution receiver executes the request */
Copy the code

Application scenarios

Sometimes you need to send a request to some object without knowing who the recipient of the request is or what operation is being requested. A loose-coupling approach is needed to design programs so that the sender and receiver can decouple from each other. — JavaScript Design Patterns and Development Practices

  1. Not paying attention to the executor, not paying attention to the execution process;
  2. Support for undoing requests, deferred processing, logging, and so on, as long as the result.

The advantages and disadvantages

  • Advantages:
    • The publisher and receiver are decoupled;
    • Extensible command to queue or log requests. (Support undo, queue, macro command and other functions).
  • Disadvantages:
    • Add additional command objects, not directly called, there is some overhead.

macros

Macro commands: A collection of commands (a product of command patterns and composite patterns)

The publisher issues a request, and the command object iterates through and executes a series of subcommands under the command set, multitasking.

// Macro command object
class MacroCommand {
  constructor() {
    this.commandList = [];  // Cache the subcommand object
  }
  add(command) {            // Add subcommands to the cache
    this.commandList.push(command);
  }
  exceute() {               // External command execution interface
    // Iterate over the self-command object and execute its execute method
    for (const command of this.commandList) { command.execute(); }}}const openWechat = {  // Command object
  execute: (a)= > {
    console.log('Open wechat'); }};const openChrome = {  // Command object
  execute: (a)= > {
    console.log('open Chrome'); }};const openEmail = {   // Command object
  execute: (a)= > {
    console.log('open the Email'); }}const macroCommand = new MacroCommand();

macroCommand.add(openWechat); // Add subcommands to macro commands
macroCommand.add(openChrome); // Add subcommands to macro commands
macroCommand.add(openEmail);  // Add subcommands to macro commands

macroCommand.execute();       // Execute macro commands
/* Open wechat open Chrome open Email */
Copy the code

Fool commands versus smart commands

Dumb command: The command object requires the receiver to execute the client’s request.

Smart command: The command object implements the request directly, without the need for a receiver, “smart” command object.

A “fool command” differs from a “smart command” in the presence of a “receiver” object.

// openWechat is an intelligent command object and no receiver is passed in
const openWechat = {
  execute: (a)= > {  // The command object processes the request directly
    console.log('Open wechat'); }};Copy the code

An intelligent command with no “receiver” is similar to the policy pattern. The code implementation is similar, but the difference is that the implementation goal is different.

  1. The goals achieved in the strategy pattern are the same, but the realization algorithms are different (e.g., goals: bonuses calculated according to KPIs);
  2. Smart commands have a broader problem to solve and a more sporadic goal. (e.g. : calculating bonuses/calculating attendance, etc.)

Refer to the article

  • JavaScript Design Patterns and Development Practices

Github is looking forward to Star! Github.com/ZengLingYon…

Author: in the name of music this article is original, there are inappropriate places welcome to point out. Reprint please indicate the source.