class Light
def initialize(location)
@location = location
end
def on
puts "#{@location} light is ON."
end
def off
puts "#{@location} light is OFF."
end
end
class Door
def initialize(location)
@location = location
end
def open
puts "#{@location} door is open."
end
def close
puts "#{@location} door is closed."
end
end
class NoCommand
def execute;end
def undo;end
end
class LightOnCommand
def initialize(light)
@light = light
end
def execute
@light.on
end
def undo
@light.off
end
end
class LightOffCommand
def initialize(light)
@light = light
end
def execute
@light.off
end
def undo
@light.on
end
end
class DoorOpenCommand
def initialize(door)
@door = door
end
def execute
@door.open
end
def undo
@door.close
end
end
class DoorCloseCommand
def initialize(door)
@door = door
end
def execute
@door.close
end
def undo
@door.open
end
end
class MacroCommand
def initialize(*commands)
@commands = commands
end
def execute
@commands.each {|cmd| cmd.execute}
end
def undo
@commands.each {|cmd| cmd.undo}
end
end
class RemoteControl
def initialize(num_slots = 7)
no_command = NoCommand.new
@on_commands = @off_commands = Array.new(7, no_command)
@undo_command = no_command
end
def set_command(slot, on_command, off_command)
@on_commands[slot] = on_command
@off_commands[slot] = off_command
end
def on_button_was_pushed(slot)
@on_commands[slot].execute
@undo_command = @on_commands[slot]
end
def off_button_was_pushed(slot)
@off_commands[slot].execute if @off_commands[slot]
@undo_command = @off_commands[slot]
end
def undo
@undo_command.undo
end
end
if __FILE__ == $0
light = Light.new('Living Door')
door = Door.new('Kitchen')
light_on = LightOnCommand.new(light)
light_off = LightOffCommand.new(light)
door_open = DoorOpenCommand.new(door)
door_close = DoorCloseCommand.new(door)
remote = RemoteControl.new
remote.set_command(0, light_on, light_off)
remote.set_command(1, door_open, door_close)
remote.on_button_was_pushed(0)
remote.on_button_was_pushed(1)
remote.off_button_was_pushed(0)
remote.undo
puts "\n---- Testing macro commands ----\n"
open_all = MacroCommand.new light_on, door_open
close_all = MacroCommand.new light_off, door_close
open_all.execute
close_all.execute
close_all.undo
end
Refactorings
No refactoring yet !
Adam
January 2, 2009, January 02, 2009 20:06, permalink
Shouldn't the object hold the state? You cannot have a light that is on and off at the same time, for example.
require 'activesupport'
class Fixture
attr_reader :location, :state
def self.has_aliases(aliases)
write_inheritable_attribute(:aliases, aliases)
aliases.each { |method_name,alias_name| alias_method(alias_name, method_name) }
end
def initialize(location, default_state = :off)
@location, @state = location, default_state
end
def aliases
self.class.read_inheritable_attribute(:aliases) || {}
end
def on
@state = :on
puts self
end
def off
@state = :off
puts self
end
def to_s
"#{location} #{self.class.to_s.downcase} is #{aliases[state] || state}"
end
end
class Light < Fixture
end
class Door < Fixture
has_aliases :on => :open, :off => :closed
end
Example in Ruby of Command design pattern from Head First Design Patterns book.