← Back to Advanced Java Course | Chapter 6: Design Patterns | Lesson 10 of 14

Java Command Pattern

The Command pattern encapsulates a request as a standalone object with an execute method, decoupling the invoker of an action from the object that actually performs it.

What is the Command Pattern?

The Command pattern encapsulates a request as a standalone object, typically with a single execute method, turning an action into something that can be stored, passed around, and invoked without the caller needing to know its details.

Example: What is the Command Pattern?

java
public class Main {
	interface Command { void execute(); }
	public static void main(String[] args) {
		Command turnOn = () -> System.out.println("Light turned on"); // a request as a standalone object
		turnOn.execute();
	}
}

Encapsulating a Request

A command decouples the object that invokes an action (the invoker) from the object that actually performs it (the receiver), since the invoker only ever calls execute on whatever command it's been given.

Example: Encapsulating a Request

java
public class Main {
	static class Light { void on() { System.out.println("Light on"); } }
	interface Command { void execute(); }
	static class LightOnCommand implements Command {
		Light light;
		LightOnCommand(Light light) { this.light = light; }
		public void execute() { light.on(); } // invoker only calls execute
	}
	public static void main(String[] args) {
		Command cmd = new LightOnCommand(new Light());
		cmd.execute();
	}
}

Undo and Redo

Adding an undo method alongside execute lets each command know how to reverse its own effect, and storing executed commands in a stack provides a natural way to implement multi-level undo and redo.

Example: Undo and Redo

java
import java.util.*;
public class Main {
	interface Command { void execute(); void undo(); }
	public static void main(String[] args) {
		StringBuilder text = new StringBuilder();
		Deque<Command> history = new ArrayDeque<>();
		Command append = new Command() {
			public void execute() { text.append("Hi"); }
			public void undo() { text.setLength(text.length() - 2); }
		};
		append.execute();
		history.push(append);
		history.pop().undo(); // reverses its own effect
		System.out.println("'" + text + "'");
	}
}

Command Queues

Because a command is just an object, multiple commands can be collected into a queue or list and processed later, in order, enabling features like task scheduling, batching, or logging of requests before they run.

Example: Command Queues

java
import java.util.*;
public class Main {
	interface Command { void execute(); }
	public static void main(String[] args) {
		Queue<Command> queue = new LinkedList<>();
		queue.add(() -> System.out.println("Task 1"));
		queue.add(() -> System.out.println("Task 2")); // collected, processed later in order
		while (!queue.isEmpty()) queue.poll().execute();
	}
}

Command vs Direct Method Calls

A direct method call tightly couples the caller to a specific class and method, while wrapping the same action in a Command object decouples them, letting the invoker work with any command without knowing what it actually does.

Example: Command vs Direct Method Calls

java
public class Main {
	static class Light { void on() { System.out.println("Light on"); } }
	interface Command { void execute(); }
	public static void main(String[] args) {
		Light light = new Light();
		light.on(); // tightly coupled direct call
		Command cmd = light::on; // decoupled -- invoker doesn't know it's a Light
		cmd.execute();
	}
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.