Skip to content

Exploring the Command Design Pattern

Posted on:September 18, 2022 at 01:13 PM

In this post, we’ll delve into the Command Design Pattern, a behavioral design pattern that encapsulates requests as objects, allowing for parameterization and queuing of requests, and providing additional functionalities like undo and redo operations.

Table of contents

Open Table of contents

Sections

The Problem: Tight Coupling

Consider a graphical user interface (GUI) program with various UI elements like buttons, text fields, and boxes. Traditionally, these UI elements would directly invoke operations in the business logic. However, this leads to tight coupling, where the UI components need to know specifics about the business logic, resulting in a less maintainable and extensible system.

CommandGraphicProblem

The Solution: Command Design Pattern

The Command Design Pattern addresses this issue by introducing a middle layer—a command—between the UI components and the business logic. Each command wraps an object and all the required information to process that command. These commands are then passed to the appropriate handler in the business logic.

CommandGraphicSolution

Key Elements of the Pattern

Command Interface:

This interface defines the execute method, which encapsulates the action to be performed.

Concrete Commands:

Classes that implement the Command interface and contain the necessary information to execute a specific action.

Invoker:

The component that triggers the execution of a command.

Receiver:

The component that performs the actual processing of the command.

Implementation Example

Let’s illustrate the pattern with a simple order processing system. We’ll have two types of commands: OrderAddCommand and OrderExecuteCommand. Both will implement the Command interface.

Command Interface

public interface Command {
    void execute();
}

Concrete Commands

OrderAddCommand

public class OrderAddCommand implements Command {
    private int id;
    private double price;

    public OrderAddCommand(int id, double price) {
        this.id = id;
        this.price = price;
    }

    @Override
    public void execute() {
        System.out.println("Order " + id + " added with price " + price);
    }
}

OrderExecuteCommand

public class OrderExecuteCommand implements Command {
    private int id;

    public OrderExecuteCommand(int id) {
        this.id = id;
    }

    @Override
    public void execute() {
        System.out.println("Order " + id + " executed");
    }
}

Command Processor

import java.util.ArrayList;
import java.util.List;

public class CommandProcessor {
    private List<Command> commands = new ArrayList<>();

    public void addCommand(Command command) {
        commands.add(command);
    }

    public void processCommands() {
        for (Command command : commands) {
            command.execute();
        }
    }
}

Client Code

public class Client {
    public static void main(String[] args) {
        CommandProcessor processor = new CommandProcessor();

        processor.addCommand(new OrderAddCommand(1, 1299.0));
        processor.addCommand(new OrderAddCommand(2, 1599.0));
        processor.addCommand(new OrderExecuteCommand(1));
        processor.addCommand(new OrderExecuteCommand(2));

        processor.processCommands();
    }
}

Conclusion

The Command Design Pattern is a powerful tool that helps in decoupling the invoker from the receiver, providing flexibility, and enabling additional functionalities like undo and redo operations. By encapsulating requests as objects, it enhances maintainability and extensibility of a software system. Understanding and applying this pattern can greatly improve the design and efficiency of your applications.

Feel free to experiment with the provided example and tailor it to suit your specific use cases. Happy coding! 🚀