Command Pattern Guide: Why Treat Requests as Objects?
Dev

Command Pattern Guide: Why Treat Requests as Objects?


In real systems, there are moments when a simple immediate function call is no longer enough. Maybe the action needs to run later, go into a queue, be retried, be logged, or even be undone. The command pattern is a classic way to model that kind of problem.

In this post, we will cover:

  • what the command pattern is
  • why requests are wrapped as objects
  • when the pattern is especially useful
  • how it connects to queuing, retries, and undo-like behavior

The key idea is that the command pattern turns a request into an object so execution timing and execution ownership can be handled more flexibly.

What is the command pattern?

The command pattern represents “something to execute” as its own object.

That means the object can carry:

  • what should happen
  • what data it should use

and then be executed later or elsewhere.

Why is that useful?

If a request exists only as an immediate function call:

  • delayed execution becomes harder
  • queueing becomes harder
  • history becomes harder to manage
  • common execution wrappers become harder to apply

When the request becomes an object, execution can be treated more like data.

When does it fit well?

  • button-triggered actions
  • job queues
  • undo/redo flows
  • batch execution
  • action history

So it fits especially well when requests need an identity of their own.

Why does it pair so naturally with queues?

A command object bundles the information needed for execution, so it works naturally with flows like:

  • put it in a queue
  • execute it later
  • retry it after failure

That is why the pattern often comes up in asynchronous and background processing discussions too.

Common misunderstandings

1. If functions already exist, wrapping them in objects is pointless

For immediate execution only, that may be true. But once execution needs to be delayed, stored, or retried, the difference becomes much more meaningful.

2. The command pattern is only for UI code

Not at all. It also fits background jobs, task runners, and automation flows very well.

3. Every action should become a command

Not necessarily. It is most useful when requests need to be handled as independent units.

Simple Example

interface Command {
  execute(): void;
}

class SendEmailCommand implements Command {
  constructor(private email: string) {}

  execute(): void {
    console.log(`Send email to ${this.email}`);
  }
}

class CommandQueue {
  private commands: Command[] = [];

  add(command: Command): void {
    this.commands.push(command);
  }

  run(): void {
    this.commands.forEach((command) => command.execute());
  }
}

const queue = new CommandQueue();
queue.add(new SendEmailCommand('team@example.com'));
queue.run();

The request becomes an object, which makes it easier to queue it, delay it, log it, or swap the executor later.

FAQ

Q. Where should beginners think about command first?

Look for cases involving delayed execution, retries, cancellation, or queueing.

Q. How is it different from strategy?

Strategy focuses more on swapping behavior, while command focuses more on packaging an executable request.

Q. Is command the same as an event?

They can feel similar, but command is more centered on an actionable execution unit.

Start Here

Continue with the core guides that pull steady search traffic.