Command Pattern

Used to decouple a sender (aka invoker) from a receiver during a command execution.

The Command Pattern has a wide variety of use cases since by decoupling the sender and the receiver in such a way that they only interact through a completely customizable interface so there is actually a lot that can be done due to this decoupling just by tweaking the interface.

Application : Literally every modern framework has Command Pattern implemented in some form or the other due the versatile application of this logic. It gives the developers (invoker) that use this framework complete customizability without actually needing to care what runs on the receiver side.

Other uses :

  1. Implement a middleware functionality in framework using Composite Command architecture
  2. Implement undo, redo mechanisms by storing command objects that contain the logic to restore a particular state.
Project Unified Modelling Language (UML) Diagram

UML Explanation....

At its core, the command pattern consists of 4 interacting bodies

Body Function
Invoker Interacts with the interface to call a specific function on the receiver side
Command It's the interface establishes and controls communication between the sender and the receiver. It declares an execute( ) method
Receivers Classes that expose methods that hold the actual implementation logic of a receiver service (eg : AddService, AuthService etc.)
ConcreteCommand A child class of the interface that defines the execute( ) method and which receiver service it shall call.

Resources

The source code for all prominent design patterns has been properly implemented and documented in this GitHub repostitory by me.‌

crew-guy/Design-Patterns
A collection of the design patterns, implemented in java, as originally created by the GoF - crew-guy/Design-Patterns

Project Description

Here, in this article, we will be building a simple application that decouples customer handling of any major services, be it Amazon or Netflix or Uber or any other company that has user authentication and management set up !!🔥‌

Implementing the Command (Interface)

An interface that establishes and manages communication between the sender and receiver
  1. On some request from sender, it creates a Command object
  2. Also, it declares the execute( ) method which shall be defined on the receiver end to run the logic that answers the sender's request.
public interface Command {
    void execute();
}
Command.java

Implementing the Receivers

These are simply class that expose methods holding some implementation logic (eg : adding a customer, authenticating a customer etc.), to anyone that instantiates them

Class Name Method exposed Function
AddCust addCust() Method for implementing the addition of a new use to a database
AuthCust authCust() Method for implementing the authentication of an existing user
public class AddService {
    public void addCustomer(){
        System.out.println("Adding a customer.....");
    }
}
AddService.java
public class AuthService {
    public void authCustomer(){
        System.out.println("Authenticating this customer.....");
    }
}
AuthenticateService.java

Implementing the ConcreteCommand

A child class of the Command interface.

It does 2 things :

  1. It instantiates all the Receiver classes so that it can access the methods they expose
  2. It defines the execute( ) method by populating it with the method call to a Receiver service using the objects of the Receiver classes

Here, we simply execute the logic for the addCust( ) or authCust( ) method by simply calling them on the objects of the AddService or AuthService class that we instantiated here.

public class AddCommand implements Command {
    private AddService addService;
    private AuthService authService;

    public AddCommand(AddService addService, AuthService authService) {
        this.addService = addService;
        this.authService = authService;
    }

    @Override
    public void execute() {
        addService.addCustomer();
        authSerive.authCustomer();
    }
}
AddCommand.java

Implementing the Invoker

A simple class that gives out an object that developers using this pattern use to execute some receiver function.
  1. Here, we simply create a Button class that calls the execute( ) method on the Command object.
  2. On clicking this Button object (instance of our Button class), a Command object is created and the execute( ) method is called on it
public class Button {
    private String label;
    private Command command;

    public Button(Command command) {
        this.command = command;
    }

    public void click() {
        command.execute();
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }
}
Button.java

Using this pattern in our application

Import all the necessary classes and modules into main.java for a final showdown of our application ! Here, I'll be show the addition as well as authentication part !

var addService = new AddService();
var authService = new authService();
var command = new AddCommand(addService, authService);
var button = new Button(addCommand);
button.click();

Here, I have done 2 things that can be changed when scaling up :

  1. I have called both the services for adding and authenticating a customer but you may choose to use an input from sender coupled with a switch statement inside the ConcreteCommand to conditionally call whichever receiver service you want
  2. You can make the receiver services extend a main Receiver interface or parent class to introduce more abstraction of the instances created in the ConcreteCommand to avoid any confusions as the size of your codebase grows because you start offering more receiver services

Conclusion

Congrats on unlocked the secret of how most modern frameworks work under the hood. You should feel pretty comfortable now developing the your own frameworks functionalities in a that contain the right balance of abstraction and control. Until next time...‌

I shall also be writing some content on using the Command Pattern to implement Composite Commands and Undo, Redo functions so do check them out !!

References..

Whatever I have learnt and implemented here in code as well as the explanation is all from the teachings of the brilliant Mosh Hamedani and his course on Design Patterns which I would recommend you to take if you are really interested in exploring the beauty of Object Oriented Programming

The Ultimate Design Pattern Series
Ace your coding job interview. Learn to write maintainable and extensible code.