🏛️ Design Principles & Patterns · Advanced

Template Method & Command in Java

Fixed skeleton with overridable steps; actions as objects.

🧩 The mysteryHow does a text editor undo your last ten actions in perfect reverse order? It turned every action into an object.

Template Method: a fixed recipe

Template Method puts the skeleton of an algorithm in a superclass method, often final. Subclasses fill in the steps: abstract steps they must supply, and *hook* methods with defaults they may override.

abstract class Report {
    final String render() {
        return header() + body();
    }
    String header() { return "#"; }
    abstract String body();
}
🔮 Predict it

Which steps run?

What does this print?

abstract class Brew {
    final void make() { boil(); add(); }
    void boil() { IO.print("B"); }
    abstract void add();
}
class Tea extends Brew {
    void boil() { IO.print("b"); }
    void add() { IO.print("t"); }
}
void main() { new Tea().make(); }
  1. bt
  2. Bt
  3. Bbt
  4. tb
Show the answer

make() fixes the order: boil() then add(). Tea overrides the boil() hook, so the base version ("B") never runs, and it supplies add(). Because make() is final, subclasses change the steps but never the order.

Inheritance vs composition

Template Method varies steps by inheritance: a subclass overrides them. Strategy varies behavior by composition: you pass in an object. The JDK's AbstractList is a textbook template: subclasses supply get() and size(), and it builds iterator(), indexOf() and more on top.

Command: an action as an object

Command packages a request as an object with execute(). The *invoker* just stores and runs commands without knowing what they do. That's why commands can be queued, logged, retried or undone. A Runnable submitted to an executor is a lightweight command.

interface Command { void execute(); }
class Remote {
    private final List<Command> queue =
        new ArrayList<>();
    void add(Command c) { queue.add(c); }
    void runAll() {
        queue.forEach(Command::execute);
    }
}
🔮 Predict it

Undo with a stack of commands

Each edit pushes an undo command. What does this print?

var text = new StringBuilder();
var undo = new ArrayDeque<Runnable>();
for (String w : List.of("hi", " there", "!")) {
    int len = text.length();
    text.append(w);
    undo.push(() -> text.setLength(len));
}
undo.pop().run();
System.out.println(text);
  1. hi there
  2. hi
  3. hi there!
Show the answer

Each command remembers the length before its edit. push puts the newest on top, so pop() returns the undo for "!" first. Running it cuts the text back to "hi there". Pop again and " there" would go too.

A smart invoker vs a dumb one

✗ Invoker knows too much
void press(String action) {
    if (action.equals("light")) light.on();
    else if (action.equals("tv")) tv.on();
}

Every new action edits the invoker, and there's no uniform way to queue or undo.

✓ Invoker just executes
void press(Command c) {
    c.execute();
    history.push(c);
}

Any command works the same way: run it, log it, undo it.

💼 In the real world

Where they show up

Thread pools run Runnable and Callable commands; job queues and retry systems store commands; editors keep undo stacks. Frameworks use Template Method for lifecycles, like HttpServlet.service() dispatching to your doGet() and doPost().

Key takeaways

  1. Template Method: final skeleton, overridable steps
  2. It varies steps by inheritance; Strategy uses composition
  3. Command: an action as an object, maybe with undo()
  4. Commands enable queues, macros and undo stacks

💡 A recipe card fixes the order of steps; a restaurant order ticket is a command waiting to be cooked.

🤯 Did you know?

The Gang of Four book links Template Method to the Hollywood Principle: "Don't call us, we'll call you." The superclass calls your steps, not the other way round.

Practice questions

What does this print?

abstract class Game {
    final void play() { turn(); end(); }
    abstract void turn();
    void end() { IO.print("E"); }
}
class Chess extends Game {
    void turn() { IO.print("T"); }
    void end() { IO.print("!"); }
}
void main() { new Chess().play(); }
  1. T!
  2. TE
  3. TE!
  4. T!E
Check your answer

T!. play() fixes the order turn() then end(). Chess supplies turn() and overrides the end() hook, so the base version never runs.

What does this print?

var doc = new StringBuilder();
var undo = new ArrayDeque<Runnable>();
for (String s : List.of("ab", "cd", "ef")) {
    int at = doc.length();
    doc.append(s);
    undo.push(() -> doc.setLength(at));
}
undo.pop().run();
undo.pop().run();
System.out.println(doc);
  1. cd
  2. abcd
  3. ab
  4. ef
Check your answer

ab. Each edit stores an undo command remembering the old length. The stack pops the newest first: undoing "ef" then "cd" leaves "ab".

Next: a traffic light that knows its own next color, with no switch statement in sight.