RO EN

Command Pattern – actions treated as independent objects

Command Pattern – actions treated as independent objects
Doru Bulubasa
15 December 2025

In real applications, user or system actions can quickly become complex: save, undo, redo, task scheduling, macros, or processing queues. If these actions are implemented directly in the UI or in the classes that trigger them, the application becomes difficult to extend and maintain.

Command Pattern solves this problem by transforming each action into an independent object that contains all the information necessary to be executed. Thus, the request is completely decoupled from the object that executes it.


What problem does the Command Pattern solve?

Without Command Pattern:

  • The UI knows the business logic

  • Actions cannot be easily undone or redone (undo/redo)

  • It is difficult to add new actions without modifying existing code

With Command Pattern:

  • Actions are standalone objects

  • You can store, log, or re-execute commands

  • You can build undo/redo mechanisms or macros


Command Pattern Structure

The pattern consists of four main components:

  1. Command – interface or abstract class that defines the Execute() method

  2. ConcreteCommand – implements the concrete command

  3. Receiver – the object that actually performs the action

  4. Invoker – the object that triggers the command

Optional:

  • Undo() – for reversing the action

  • Command History – for storing executed commands


Conceptual Diagram (description)

Invoker → Command → Receiver

The invoker does not know what the command does, only that it executes it.


Simple example in C#

1. Command Interface

public interface ICommand
{
    void Execute();
}

2. Receiver – business logic

public class Light
{
    public void TurnOn()
    {
        Console.WriteLine("The light has been turned on");
    }

    public void TurnOff()
    {
        Console.WriteLine("The light has been turned off");
    }
}

3. Concrete Commands

public class TurnOnLightCommand : ICommand
{
    private readonly Light _light;

    public TurnOnLightCommand(Light light)
    {
        _light = light;
    }

    public void Execute()
    {
        _light.TurnOn();
    }
}
public class TurnOffLightCommand : ICommand
{
    private readonly Light _light;

    public TurnOffLightCommand(Light light)
    {
        _light = light;
    }

    public void Execute()
    {
        _light.TurnOff();
    }
}

4. Invoker

public class RemoteControl
{
    private ICommand _command;

    public void SetCommand(ICommand command)
    {
        _command = command;
    }

    public void PressButton()
    {
        _command.Execute();
    }
}

5. Usage

var light = new Light();

var turnOn = new TurnOnLightCommand(light);
var turnOff = new TurnOffLightCommand(light);

var remote = new RemoteControl();

remote.SetCommand(turnOn);
remote.PressButton();

remote.SetCommand(turnOff);
remote.PressButton();

Undo / Redo Implementation

Command Pattern becomes extremely powerful when we add support for undo.

Extending the interface

public interface ICommand
{
    void Execute();
    void Undo();
}

Command with Undo

public class TurnOnLightCommand : ICommand
{
    private readonly Light _light;

    public TurnOnLightCommand(Light light)
    {
        _light = light;
    }

    public void Execute()
    {
        _light.TurnOn();
    }

    public void Undo()
    {
        _light.TurnOff();
    }
}

Command History

public class CommandManager
{
    private readonly Stack<ICommand> _history = new();

    public void ExecuteCommand(ICommand command)
    {
        command.Execute();
        _history.Push(command);
    }

    public void Undo()
    {
        if (_history.Any())
        {
            var command = _history.Pop();
            command.Undo();
        }
    }
}

Real examples where Command Pattern is used

  • Undo / Redo in editors (Word, Photoshop)

  • Menu systems and buttons

  • Task queues and job scheduling

  • Macros (chain execution of commands)

  • CQRS (Command side)


Advantages

✔️ Complete decoupling between UI and business logic

✔️ Extensibility without modifying existing code

✔️ Native support for undo/redo

✔️ Easy testing of individual commands


Disadvantages

❌ Increases the number of classes

❌ Can be overkill for simple applications


Command Pattern vs Strategy Pattern

Command

Strategy

Represents an action

Represents an algorithm

Can be stored

Usually not

Supports undo/redo

No

One-time execution

Long-term behavior

 


Conclusion

Command Pattern is an essential pattern for modern and extensible applications. When actions become independent objects, the application gains flexibility, testability, and control.

If you need undo/redo, processing queues, or macros, Command Pattern is the right choice.