Jinal Desai

My thoughts and learnings

Demystifying Design Patterns: Command Design Pattern

Demystifying Design Patterns: Command Design Pattern
  1. Demystifying Design Patterns: Singleton Design Pattern
  2. Demystifying Design Patterns: Factory Method Design Pattern
  3. Demystifying Design Patterns: Abstract Factory Design Pattern
  4. Demystifying Design Patterns: Builder Design Pattern
  5. Demystifying Design Patterns: Prototype Design Pattern
  6. Demystifying Design Patterns: Adapter Design Pattern
  7. Demystifying Design Patterns: Bridge Design Pattern
  8. Demystifying Design Patterns: Composite Design Pattern
  9. Demystifying Design Patterns: Decorator Design Pattern
  10. Demystifying Design Patterns: Proxy Design Pattern
  11. Demystifying Design Patterns: Observer Design Pattern
  12. Demystifying Design Patterns: Strategy Design Pattern
  13. Demystifying Design Patterns: Command Design Pattern
  14. Demystifying Design Patterns: State Design Pattern
  15. Demystifying Design Patterns: Chain of Responsibility Design Pattern
  16. Demystifying Design Patterns: Visitor Design Pattern
  17. Demystifying Design Patterns: Template Method Design Pattern

Welcome to the 13th installment of our series on Demystifying Design Patterns! In this article, we embark on a journey into the world of the Command Design Pattern. This behavioral pattern enables you to encapsulate requests as objects, allowing you to parameterize clients with queues, requests, and operations. Join us as we explore the intricacies of this pattern, its practical applications, real-life examples, and provide code implementations in Java, C#, and Python.

Commanding Actions with the Command Pattern

The Command Design Pattern focuses on encapsulating a request as an object. It decouples the sender of a request (the client) from the receiver (the object that performs the action). This decoupling enables you to parameterize clients with various types of requests, delay or queue requests for execution, and even support undoable operations.

Undo and Redo Functionality

One of the standout features of the Command Pattern is its ability to support undo and redo functionality effortlessly. By storing the state of the receiver before executing a command, you can roll back operations, effectively implementing an “undo” feature. Conversely, you can also implement “redo” by storing the state changes during undo operations.

Implementing Command Queues

Command Queues play a vital role in scenarios where you need to manage and schedule commands for execution. These queues can be used to implement features like job scheduling, task management, and more. The Command Pattern ensures that each command is an encapsulated entity that can be easily queued and executed when needed.

Real-World Applications of Command Pattern

The Command Pattern finds application in various real-world scenarios:

Example 1: Remote Controls

Consider a universal remote control that operates multiple devices like TVs, sound systems, and lights. Each button press on the remote represents a command, whether it’s turning on the TV or increasing the volume. The remote control encapsulates these commands, allowing you to queue and execute them as needed.

Example 2: Text Editors

Text editors often provide undo and redo functionality. Each edit action, such as typing characters, deleting text, or formatting, can be encapsulated as a command. The editor maintains a history of these commands, enabling users to undo or redo their actions.

Example 3: Database Transactions

In database systems, the Command Pattern is used to encapsulate SQL statements or database operations as commands. These commands can be executed and undone, making it possible to maintain data consistency during transactions.

Code Examples

Now, let’s explore the Command Pattern with code examples in Java, C#, and Python to illustrate its implementation.

example-command-design-pattern

Java Example:
// (Java code example illustrating the Command Pattern)
import java.util.*;

// Command interface
interface Command {
    void execute();
    void undo();
}

// Receiver
class Light {
    public void turnOn() {
        System.out.println("Light is ON");
    }
    
    public void turnOff() {
        System.out.println("Light is OFF");
    }
}

// Concrete Command classes
class TurnOnLightCommand implements Command {
    private Light light;
    
    public TurnOnLightCommand(Light light) {
        this.light = light;
    }
    
    public void execute() {
        light.turnOn();
    }
    
    public void undo() {
        light.turnOff();
    }
}

class TurnOffLightCommand implements Command {
    private Light light;
    
    public TurnOffLightCommand(Light light) {
        this.light = light;
    }
    
    public void execute() {
        light.turnOff();
    }
    
    public void undo() {
        light.turnOn();
    }
}

// Invoker
class RemoteControl {
    private List history = new ArrayList<>();
    
    public void pushButton(Command command) {
        command.execute();
        history.add(command);
    }
    
    public void undoLast() {
        if (!history.isEmpty()) {
            Command lastCommand = history.remove(history.size() - 1);
            lastCommand.undo();
        }
    }
}

public class CommandPatternDemo {
    public static void main(String[] args) {
        Light livingRoomLight = new Light();
        
        Command turnOnCommand = new TurnOnLightCommand(livingRoomLight);
        Command turnOffCommand = new TurnOffLightCommand(livingRoomLight);
        
        RemoteControl remote = new RemoteControl();
        remote.pushButton(turnOnCommand);
        remote.pushButton(turnOffCommand);
        
        // Undo the last command
        remote.undoLast();
    }
}
C# Example:
// (C# code example illustrating the Command Pattern)
using System;
using System.Collections.Generic;

// Command interface
interface ICommand {
    void Execute();
    void Undo();
}

// Receiver
class Light {
    public void TurnOn() {
        Console.WriteLine("Light is ON");
    }

    public void TurnOff() {
        Console.WriteLine("Light is OFF");
    }
}

// Concrete Command classes
class TurnOnLightCommand : ICommand {
    private Light light;

    public TurnOnLightCommand(Light light) {
        this.light = light;
    }

    public void Execute() {
        light.TurnOn();
    }

    public void Undo() {
        light.TurnOff();
    }
}

class TurnOffLightCommand : ICommand {
    private Light light;

    public TurnOffLightCommand(Light light) {
        this.light = light;
    }

    public void Execute() {
        light.TurnOff();
    }

    public void Undo() {
        light.TurnOn();
    }
}

// Invoker
class RemoteControl {
    private List history = new List();

    public void PushButton(ICommand command) {
        command.Execute();
        history.Add(command);
    }

    public void UndoLast() {
        if (history.Count > 0) {
            ICommand lastCommand = history[history.Count - 1];
            lastCommand.Undo();
            history.RemoveAt(history.Count - 1);
        }
    }
}

class CommandPatternDemo {
    static void Main(string[] args) {
        Light livingRoomLight = new Light();

        ICommand turnOnCommand = new TurnOnLightCommand(livingRoomLight);
        ICommand turnOffCommand = new TurnOffLightCommand(livingRoomLight);

        RemoteControl remote = new RemoteControl();
        remote.PushButton(turnOnCommand);
        remote.PushButton(turnOffCommand);

        // Undo the last command
        remote.UndoLast();
    }
}
Python Example:
# (Python code example illustrating the Command Pattern)
# Command interface
class Command:
    def execute(self):
        pass

    def undo(self):
        pass

# Receiver
class Light:
    def turn_on(self):
        print("Light is ON")

    def turn_off(self):
        print("Light is OFF")

# Concrete Command classes
class TurnOnLightCommand(Command):
    def __init__(self, light):
        self.light = light

    def execute(self):
        self.light.turn_on()

    def undo(self):
        self.light.turn_off()

class TurnOffLightCommand(Command):
    def __init__(self, light):
        self.light = light

    def execute(self):
        self.light.turn_off()

    def undo(self):
        self.light.turn_on()

# Invoker
class RemoteControl:
    def __init__(self):
        self.history = []

    def push_button(self, command):
        command.execute()
        self.history.append(command)

    def undo_last(self):
        if self.history:
            last_command = self.history.pop()
            last_command.undo()

if __name__ == "__main__":
    living_room_light = Light()

    turn_on_command = TurnOnLightCommand(living_room_light)
    turn_off_command = TurnOffLightCommand(living_room_light)

    remote = RemoteControl()
    remote.push_button(turn_on_command)
    remote.push_button(turn_off_command)

    # Undo the last command
    remote.undo_last()

Conclusion

The Command Design Pattern is a powerful tool for encapsulating requests as objects, supporting undo and redo functionality, and implementing command queues. It finds practical application in various domains, from remote controls to text editors and database systems.

In this article, we explored the core concepts of the Command Pattern and its real-world applications. We also provided code examples in Java, C#, and Python to help you implement the pattern in your projects.

With the Command Pattern in your arsenal, you can design more flexible and robust systems, enabling users to execute, undo, and redo actions seamlessly. Stay tuned for the next installment in our Demystifying Design Patterns series!

Leave a Reply

Your email address will not be published. Required fields are marked *