CodeDifficulty: Intermediate3 min

Command Template in Python, Java and TypeScript

A command with execute() and undo(), an invoker that keeps a history, and one undo.

The Command template is the pattern in its pure form, with the participant names from the class diagram. An invoker runs two commands that add to a receiver's value, then undoes the last one. The steps add each participant in Python, and the tabs give the complete program in three languages, each with its output.

Building the template one participant at a time

Receiver

Holds the state and does the work. Here the work is a number that changes.

py
class Receiver:
    def __init__(self) -> None:
        self.value = 0

Command

Declares how to carry out a request, and how to reverse it.

py
class Command(ABC):
    @abstractmethod
    def execute(self) -> None: ...

    @abstractmethod
    def undo(self) -> None: ...

Concrete command

Holds the receiver and the request's argument, which is all its undo needs.

py
def execute(self) -> None:
    self._receiver.value += self._amount

def undo(self) -> None:
    self._receiver.value -= self._amount

Invoker

Runs each command and keeps it, so the last one can be undone.

py
def run(self, command: Command) -> None:
    command.execute()
    self._history.append(command)

def undo_last(self) -> None:
    self._history.pop().undo()

The complete template

py
from abc import ABC, abstractmethod


class Receiver:
    def __init__(self) -> None:
        self.value = 0


class Command(ABC):
    @abstractmethod
    def execute(self) -> None: ...

    @abstractmethod
    def undo(self) -> None: ...


class AddCommand(Command):
    def __init__(self, receiver: Receiver, amount: int) -> None:
        self._receiver = receiver
        self._amount = amount

    def execute(self) -> None:
        self._receiver.value += self._amount

    def undo(self) -> None:
        self._receiver.value -= self._amount


class Invoker:
    def __init__(self) -> None:
        self._history: list[Command] = []

    def run(self, command: Command) -> None:
        command.execute()
        self._history.append(command)

    def undo_last(self) -> None:
        self._history.pop().undo()


receiver = Receiver()
invoker = Invoker()
invoker.run(AddCommand(receiver, 5))
print("after add 5:", receiver.value)
invoker.run(AddCommand(receiver, 3))
print("after add 3:", receiver.value)
invoker.undo_last()
print("after undo:", receiver.value)
OutputRan with python:3.12-slim (Python 3.12.13)
after add 5: 5
after add 3: 8
after undo: 5
The history is a list used as a stack: `append` on run, `pop` on undo.
java
import java.util.ArrayDeque;
import java.util.Deque;

public class CmTemplate {
    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        Invoker invoker = new Invoker();
        invoker.run(new AddCommand(receiver, 5));
        System.out.println("after add 5: " + receiver.value);
        invoker.run(new AddCommand(receiver, 3));
        System.out.println("after add 3: " + receiver.value);
        invoker.undoLast();
        System.out.println("after undo: " + receiver.value);
    }
}

class Receiver {
    int value;
}

interface Command {
    void execute();

    void undo();
}

class AddCommand implements Command {
    private final Receiver receiver;
    private final int amount;

    AddCommand(Receiver receiver, int amount) {
        this.receiver = receiver;
        this.amount = amount;
    }

    public void execute() {
        receiver.value += amount;
    }

    public void undo() {
        receiver.value -= amount;
    }
}

class Invoker {
    private final Deque<Command> history = new ArrayDeque<>();

    void run(Command command) {
        command.execute();
        history.push(command);
    }

    void undoLast() {
        history.pop().undo();
    }
}
OutputRan with eclipse-temurin:21-jdk (Java 21.0.12)
after add 5: 5
after add 3: 8
after undo: 5
`ArrayDeque` with `push` and `pop` is Java's usual stack.
ts
class Receiver {
  value = 0;
}

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

class AddCommand implements Command {
  constructor(
    private readonly receiver: Receiver,
    private readonly amount: number,
  ) {}

  execute(): void {
    this.receiver.value += this.amount;
  }

  undo(): void {
    this.receiver.value -= this.amount;
  }
}

class Invoker {
  private readonly history: Command[] = [];

  run(command: Command): void {
    command.execute();
    this.history.push(command);
  }

  undoLast(): void {
    this.history.pop()?.undo();
  }
}

const receiver = new Receiver();
const invoker = new Invoker();
invoker.run(new AddCommand(receiver, 5));
console.log("after add 5:", receiver.value);
invoker.run(new AddCommand(receiver, 3));
console.log("after add 3:", receiver.value);
invoker.undoLast();
console.log("after undo:", receiver.value);
OutputRan with node:22-slim (Node 22.23.1), TypeScript 5.9.3
after add 5: 5
after add 3: 8
after undo: 5
`pop()?.undo()` does nothing when the history is empty.

The value goes to 5, then 8, and the undo takes it back to 5. The invoker never mentions AddCommand or Receiver; a second kind of command would join the same history. Each AddCommand can undo itself because subtracting its amount exactly reverses adding it. A command whose change cannot be reversed from its arguments must store more than that.