CODESAMPLE
Command - Ruby
The Command pattern encapsulates a request as an object, allowing parameterization of clients with different requests, queueing or logging of requests, and support for undoable operations. This example represents simple calculator operations (add, subtract) as commands. Each command has an execute method that performs the operation on a Calculator receiver. The execute method stores the previous value enabling a simplistic undo functionality. Ruby’s flexibility lends itself well to this pattern; we utilize classes to represent commands, making them first-class objects, and the call method for a command-like interface, fitting with the language’s object-oriented nature.
# Receiver
class Calculator
attr_accessor :current
def initialize(current = 0)
@current = current
end
def add(value)
@previous = @current
@current += value
end
def subtract(value)
@previous = @current
@current -= value
end
def current_value
@current
end
end
# Command Interface
class Command
def initialize(calculator)
@calculator = calculator
end
def execute
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
def undo
#Basic Undo based on previous state. More complex undo could involve arguments.
@calculator.current = @calculator.previous if defined? @calculator.previous
end
end
# Concrete Commands
class AddCommand < Command
def initialize(calculator, value)
super(calculator)
@value = value
end
def execute
@calculator.add(@value)
end
end
class SubtractCommand < Command
def initialize(calculator, value)
super(calculator)
@value = value
end
def execute
@calculator.subtract(@value)
end
end
# Invoker
class Invoker
def initialize
@commands = []
end
def add_command(command)
@commands << command
end
def execute_commands
@commands.each do |command|
command.execute
end
end
def undo_all
@commands.reverse_each do |command|
command.undo
end
end
end
# Example Usage
calculator = Calculator.new
invoker = Invoker.new
add_command = AddCommand.new(calculator, 10)
subtract_command = SubtractCommand.new(calculator, 5)
invoker.add_command(add_command)
invoker.add_command(subtract_command)
invoker.execute_commands
puts "Current value: #{calculator.current_value}" # Output: Current value: 5
invoker.undo_all
puts "Current value after undo: #{calculator.current_value}" # Output: Current value after undo: 0