Command Pattern in Typescript

Command is a behavioral design pattern that turns a request into a stand-alone object that contains all information about the request. This transformation lets you parameterize methods with different requests, delay or queue a request’s execution, and support undoable operations.

In object-oriented programming, the command pattern is a behavioral design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time. This information includes the method name, the object that owns the method and values for the method parameters.

Four terms always associated with the command pattern are command, receiver, invoker and client. A command object has a receiver object and invokes a method of the receiver in a way that is specific to that receiver’s class. The receiver then does the work. A command object is separately passed to an invoker object, which invokes the command, and optionally does bookkeeping about the command execution. Any command object can be passed to the same invoker object. Both an invoker object and several command objects are held by a client object. The client contains the decision making about which commands to execute at which points. To execute a command, it passes the command object to the invoker object.

Using command objects makes it easier to construct general components that need to delegate, sequence or execute method calls at a time of their choosing without the need to know the class of the method or the method parameters. Using an invoker object allows bookkeeping about command executions to be conveniently performed, as well as implementing different modes for commands, which are managed by the invoker object, without the need for the client to be aware of the existence of bookkeeping or modes.

Design principles utilized by the command pattern

Separation of concerns: The remote will know how to make a request but is not concerned with what happens or how the request is executed.

Programming to an Interface : Because each request is an implementation of the same interface, it allows new command objects to be created independently without altering any previously written code.

Low coupling: The command objects only interact with other classes when a request is made for a particular action without sharing any other information. Due to this, changes in one class’s implementation won’t affect how the other class communicates with it.

Class diagram depicting a generic command pattern implementation.

Use cases for the Command Pattern

  • Plugin development. Consider what a plugin is: an encapsulated behavior that you can inject into existing client code that will execute it, without really having any context about its internal logic. That fits perfectly inside the command pattern.

  • Undo actions. Every command has a very distinct logic and it can also keep a state associated with that logic. For example, the state of the object you’re using or modifying through your command right before the command’s execute method is called. That way, you can also add an undo method, that will reverse the changes done by the command. This pattern makes implementing the “Undo” functionality surprisingly easy.