0e34c56054c414263e933a1b8b3d0d55

Example in Ruby of Command design pattern from Head First Design Patterns book.

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 !

A8d3f35baafdaea851914b17dae9e1fc

Adam

January 2, 2009, January 02, 2009 20:06, permalink

No rating. Login to rate!

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

Your refactoring





Format Copy from initial code

or Cancel