Command Design Pattern in Ruby

1. Definition

The Command Design Pattern encapsulates a request as an object, thereby allowing for parameterization of clients with different requests, queuing of requests, and logging the operations. It also provides support for undoable operations.

2. Problem Statement

Consider a scenario where you have various operations or requests, and you want to decouple the objects that invoke these operations from the objects that perform them. You might also want the flexibility to queue, log, or support undo-redo functionalities for these operations.

3. Solution

Command pattern introduces command objects. Each command object knows how to perform an operation, and it decouples the invoker from the receiver. You can queue commands, log them, or even implement undo and redo features.

4. Real-World Use Cases

1. Remote control system where each button press is a command.

2. Task scheduling or job queue systems.

3. Undo-redo functionality in software like word processors or graphic editors.

5. Implementation Steps

1. Define a command interface with an 'execute' method.

2. Create one or more concrete classes that implement this command interface for specific actions.

3. Define an invoker class to keep and execute these commands.

6. Implementation in Ruby

# Step 1: Command Interface
class Command
  def execute
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end
# Step 2: Concrete Command Classes
class LightOnCommand < Command
  def initialize(light)
    @light = light
  end
  def execute
    @light.turn_on
  end
end
class LightOffCommand < Command
  def initialize(light)
    @light = light
  end
  def execute
    @light.turn_off
  end
end
# Receiver class
class Light
  def turn_on
    "Light is ON"
  end
  def turn_off
    "Light is OFF"
  end
end
# Step 3: Invoker Class
class RemoteControl
  def submit(command)
    command.execute
  end
end
# Client code
light = Light.new
turn_on = LightOnCommand.new(light)
turn_off = LightOffCommand.new(light)
remote = RemoteControl.new
puts remote.submit(turn_on)
puts remote.submit(turn_off)

Output:

Light is ON
Light is OFF

Explanation:

1. Command is an interface that declares the execute method.

2. LightOnCommand and LightOffCommand are concrete commands that encapsulate a request to a Light object.

3. RemoteControl is an invoker. It asks the command to carry out the request.

4. In the client code, we initialize a Light, wrap its on and off operations with respective commands, and then use a RemoteControl to invoke these commands.

7. When to use?

Use the Command Pattern when:

1. You need to decouple an object that invokes an operation from the one that knows how to perform it.

2. You want to support undo, redo, or other queue and logging operations.

3. You want to parameterize objects with operations.


Comments