Skip to main content

Explain the Command Pattern in iOS

· 3 min read
Szymon Michalak
iOS Developer
Sources & Resources

Main Source: Ray Wenderlich - Design Patterns by Tutorials (2019)
Further Reading:

TL/DR

The Command Pattern encapsulates requests or actions into objects. This allows you to parameterize methods, queue operations, and support undo functionality.

Concept Overview​

The Command Pattern is a behavioral design pattern that turns a request or action into a command object, which can then be executed, delayed, or queued. The three primary components are:

  1. Invoker: Stores and executes commands.
  2. Command: Encapsulates the action to be performed.
  3. Receiver: The object that the command is performed on.

This pattern is often used in situations where actions need to be executed at a later time or reversed (for undo functionality).

Playground Example​

Below is an example based on a door control system from the book:

import Foundation

// MARK: - Receiver
public class Door {
public var isOpen = false
}

// MARK: - Command
public class DoorCommand {
public let door: Door
public init(_ door: Door) {
self.door = door
}
public func execute() {}
}

public class OpenCommand: DoorCommand {
public override func execute() {
print("Opening the door...")
door.isOpen = true
}
}

public class CloseCommand: DoorCommand {
public override func execute() {
print("Closing the door...")
door.isOpen = false
}
}

// MARK: - Invoker
public class Doorman {
public let commands: [DoorCommand]
public let door: Door

public init(door: Door) {
let commandCount = arc4random_uniform(10) + 1
self.commands = (0..<commandCount).map { index in
return index % 2 == 0 ? OpenCommand(door) : CloseCommand(door)
}
self.door = door
}

public func execute() {
print("Doorman is executing commands...")
commands.forEach { $0.execute() }
}
}

// Example usage
let door = Door()
let doorman = Doorman(door: door)
doorman.execute()

How It Works:​

  • Receiver: The Door class acts as the receiver that will be opened or closed by the command.
  • Command: The OpenCommand and CloseCommand encapsulate the actions of opening and closing the door.
  • Invoker: The Doorman class stores and executes the commands in sequence.

When to Use​

  • Queuing and executing actions: When you need to queue operations to be performed later, or support undo functionality.
  • Decoupling requesters from executors: When the requester (e.g., user interface) should be decoupled from the object that performs the action.

When to Be Careful​

  • Complex command objects: Be cautious of creating too many command objects, as it can lead to more complex and harder-to-maintain code.

In Bullets
  • The Command Pattern turns actions into objects that can be stored and executed later.
  • It involves three main components: invoker, command, and receiver.
  • Useful for queuing, undo functionality, or decoupling requesters from actions.