skip to content

Command Pattern - Simplify operation execution

Updated: at 12:00 AM

1. The Problem

Problem: “I want to trigger actions without knowing who performs them or how.”

Real systems often need to execute operations decoupled from the object that performs them:

Without abstraction, code ends up hard-wired:

if action == "turn_on_light": light.on()
elif action == "turn_off_light": light.off()
elif action == "increase_temp": ac.increase()

This leads to:

We need a way to represent actions as objects.

2. The Command Pattern: Treat Actions as First-Class Objects

Command Pattern turns an operation call into a reusable object.

Core idea:

A Command system has:

Benefits:

Use Command when:

3. Implementation in Python

Command Interface

from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

    def undo(self):
        pass

Example 1: Light Commands

Receiver

class Light:
    def on(self):
        print("Light is ON")

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

Concrete Commands

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

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

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


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

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

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

Example 2: AC Commands

Receiver

class AirConditioner:
    def __init__(self):
        self.temp = 24

    def turn_on(self):
        print("AC ON")

    def turn_off(self):
        print("AC OFF")

    def increase_temp(self):
        self.temp += 1
        print(f"AC Temp Increased to {self.temp}")

    def decrease_temp(self):
        self.temp -= 1
        print(f"AC Temp Decreased to {self.temp}")

Commands

class ACOnCommand(Command):
    def __init__(self, ac: AirConditioner):
        self.ac = ac

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

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


class IncreaseTempCommand(Command):
    def __init__(self, ac: AirConditioner):
        self.ac = ac

    def execute(self):
        self.ac.increase_temp()

    def undo(self):
        self.ac.decrease_temp()

Invoker

Invoker doesn’t know what action does. It only calls execute().

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

    def submit(self, command: Command):
        command.execute()
        self.history.append(command)

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

Usage

light = Light()
ac = AirConditioner()

remote = RemoteControl()

remote.submit(LightOnCommand(light))
remote.submit(ACOnCommand(ac))
remote.submit(IncreaseTempCommand(ac))

remote.undo_last()     # undo increase temperature
remote.undo_last()     # undo AC on

4. Meta Command / Macro Command

A Meta Command (Macro Command) lets you bundle multiple commands as one.

Example: “Evening Mode”

class MacroCommand(Command):
    def __init__(self, commands):
        self.commands = commands

    def execute(self):
        for cmd in self.commands:
            cmd.execute()

    def undo(self):
        # Reverse execution order
        for cmd in reversed(self.commands):
            cmd.undo()

Usage

macro = MacroCommand([
    LightOnCommand(light),
    ACOnCommand(ac),
    IncreaseTempCommand(ac),
    IncreaseTempCommand(ac),
])

remote.submit(macro)
remote.undo_last()

You now have a single command that represents a complex behavior.

5. When to Use Command (and When Not To)

You should use Command when:

You should not use Command when: