Command encapsulates a request as a standalone object, so it can be queued, logged, undone, or passed around independently of whatever code originally triggered it.
public interface ICommand
{
void Execute();
void Undo();
}
public class AddTextCommand : ICommand
{
private readonly StringBuilder _document;
private readonly string _text;
public AddTextCommand(StringBuilder document, string text)
{
_document = document;
_text = text;
}
public void Execute() => _document.Append(_text);
public void Undo() => _document.Remove(_document.Length - _text.Length, _text.Length);
}
public class CommandHistory
{
private readonly Stack<ICommand> _history = new();
public void Execute(ICommand command)
{
command.Execute();
_history.Push(command);
}
public void UndoLast()
{
if (_history.Count > 0) _history.Pop().Undo();
}
}
var document = new StringBuilder();
var history = new CommandHistory();
history.Execute(new AddTextCommand(document, "Hello"));
history.Execute(new AddTextCommand(document, ", world"));
history.UndoLast(); // removes ", world" — document is back to "Hello"
This is exactly how undo/redo stacks in editors are implemented, and the same shape underlies background job queues — a SendEmailCommand or ProcessPaymentCommand object can be serialized, stored, and executed later by a worker process with no knowledge of where or why it was originally created.