Design Pattern 19: Command Pattern - Complete Guide with Undo/Redo and Remote Control Examples

πŸ“ Download the complete Design Pattern series code from our design_pattern repository.


🎯 What is the Command Pattern?

The Command Pattern is a behavioral design pattern that encapsulates a request as an object, allowing you to parameterize clients, queue or log requests, and support undoable operations. It decouples the object that invokes the operation from the one that knows how to perform it.

Key Benefits:

  • βœ… Decouples sender and receiver
  • βœ… Supports undo/redo
  • βœ… Flexible command history
  • βœ… Extensible for new commands
  • βœ… Centralizes control logic

πŸš€ Real-World Problem: Music Player Remote Control

Suppose you are building a music player remote control system with the following requirements:

  • Users can control play, pause, and stop via remote
  • Support for undo (e.g., undo pause resumes play)
  • Button actions should be flexible for future features (e.g., next, repeat)

Business Rules:

  • All actions are encapsulated as command objects
  • Remote control manages command history for undo
  • Easy to add new commands without changing existing code

πŸ—οΈ Object-Oriented Analysis (OOA)

Identified Forces:

  1. High coupling - Client must know all device details
  2. Lack of flexibility - Hard to add new devices or actions
  3. Undo/redo complexity - No unified way to manage history

πŸ’‘ Command Pattern Solution

By encapsulating actions as command objects, we decouple the invoker from the receiver and enable flexible, extensible control.

Command Pattern Components:

  • Receiver - Executes the actual operation
  • Command Interface - Defines execute/undo
  • Concrete Command - Implements specific actions
  • Invoker - Triggers commands and manages history
  • Client - Sets up relationships

πŸ› οΈ Implementation: Music Player Remote Control

1. Receiver: Music Player

class MusicPlayer {
    fun play() { println("Music is playing") }
    fun pause() { println("Music is paused") }
    fun stop() { println("Music is stopped") }
}

2. Command Interface

interface Command {
    fun execute()
    fun undo()
}

3. Concrete Commands

class PlayCommand(private val player: MusicPlayer) : Command {
    override fun execute() { player.play() }
    override fun undo() { player.pause() }
}
class PauseCommand(private val player: MusicPlayer) : Command {
    override fun execute() { player.pause() }
    override fun undo() { player.play() }
}
class StopCommand(private val player: MusicPlayer) : Command {
    override fun execute() { player.stop() }
    override fun undo() { println("Cannot undo stop") }
}

4. Invoker: Remote Control

class RemoteControl {
    private val commandHistory = mutableListOf<Command>()
    fun pressButton(command: Command) {
        command.execute()
        commandHistory.add(command)
    }
    fun pressUndo() {
        if (commandHistory.isNotEmpty()) {
            val lastCommand = commandHistory.removeLast()
            lastCommand.undo()
        } else {
            println("No command to undo")
        }
    }
}

5. Client Code

fun main() {
    val player = MusicPlayer()
    val playCommand = PlayCommand(player)
    val pauseCommand = PauseCommand(player)
    val stopCommand = StopCommand(player)
    val remoteControl = RemoteControl()
    remoteControl.pressButton(playCommand)
    remoteControl.pressButton(pauseCommand)
    remoteControl.pressUndo()
    remoteControl.pressButton(stopCommand)
    remoteControl.pressUndo()
}

Expected Output:

Music is playing
Music is paused
Music is playing
Music is stopped

πŸ“Š Command Pattern vs Alternative Approaches

Approach Pros Cons
Command Pattern βœ… Decouples sender/receiver
βœ… Undo/redo support
❌ More classes
❌ Command management overhead
Direct Calls βœ… Simple for small apps ❌ High coupling
❌ No undo/redo
Event Bus βœ… Decoupled communication ❌ Harder to trace logic
❌ Global state

🎯 When to Use the Command Pattern

βœ… Perfect For:

  • Remote controls (music, TV, smart home)
  • Undo/redo systems
  • Macro recording/playback
  • Task scheduling and queuing
  • GUI button actions

❌ Avoid When:

  • Simple, one-off actions
  • Small, stateless systems

πŸ”§ Advanced Command Pattern Implementations

  • Macro commands (batch actions)
  • Command logging and replay
  • Asynchronous command execution
  • Command queues and scheduling

πŸ“ˆ Real-World Applications

  • Remote controls (TV, music, smart home)
  • Text editors (undo/redo)
  • Transaction management
  • Workflow engines

🚨 Common Pitfalls and Best Practices

  • Avoid excessive command classes (use parameterized commands)
  • Document command history logic
  • Use clear naming for commands


βœ… Conclusion

Through the Command Pattern, we successfully decoupled operations, enabled undo/redo, and made the system more flexible and extensible.

Key Advantages:

  • 🎯 Decouples sender and receiver
  • πŸ”§ Undo/redo support
  • πŸ“ˆ Flexible command history
  • πŸ›‘οΈ Maintainability
  • ⚑ Extensibility

Design Principles Followed:

  • Single Responsibility Principle (SRP): Each command has one responsibility
  • Open-Closed Principle (OCP): Add new commands easily
  • Don’t Repeat Yourself (DRY): Centralize command logic

Perfect For:

  • Remote controls
  • Undo/redo systems
  • Workflow engines

The Command Pattern provides an elegant solution for flexible, extensible control in modern applications!


πŸ’‘ Pro Tip: Use macro commands and command logging for advanced automation and debugging.

πŸ”” Stay Updated: Follow our Design Pattern series for more software architecture insights!




    Enjoy Reading This Article?

    Here are some more articles you might like to read next:

  • How to Use Multiple GitHub Accounts on One Computer: Complete SSH Setup Guide
  • Excalidraw AI: Create Professional Diagrams with Text Commands - Complete Guide
  • Complete macOS Development Environment Setup Guide for 2024
  • Design Pattern 28: Interpreter Pattern - Complete Guide with Examples
  • Design Pattern 27: Visitor Pattern - Complete Guide with Real-World IoT Examples