Created
June 17, 2009 22:41
-
-
Save laktek/131562 to your computer and use it in GitHub Desktop.
Vending Machine with multiple beverages (using State Pattern and a Singleton class)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'singleton' | |
class State | |
attr_accessor :machine | |
STATES = {:ready => "Ready", :listen => "Listen", :processing => "Processing"} | |
def initialize(machine) | |
@machine = machine | |
end | |
def insert_coin; end | |
def return_coin; end | |
def select(beverage); end | |
def get_beverage; end | |
def transit_to(state, options={}) | |
machine.state = eval(STATES[state]).new @machine | |
end | |
end | |
class Ready < State | |
def insert_coin | |
if machine.processor.beverages_available? | |
transit_to :listen | |
return "Select what do you like to have" | |
else | |
return "Sorry out of beverages!" | |
end | |
end | |
def return_coin | |
return "You haven't inserted a coin" | |
end | |
def select(beverage) | |
return "Insert a coin before selecting a beverage" | |
end | |
def get_beverage | |
return "First you need to insert a coin" | |
end | |
end | |
class Listen < State | |
def insert_coin | |
return "Sorry! please wait till I finish the current order" | |
end | |
def return_coin | |
transit_to :ready | |
return "Here is your coin." | |
end | |
def select(beverage) | |
if machine.processor.make(beverage) | |
transit_to :processing | |
return "Please wait! Your #{beverage} will be ready in couple of minutes." | |
else | |
return_coin | |
return "Sorry #{beverage} is not available today" | |
end | |
end | |
def get_beverage | |
return "You need to select a beverage" | |
end | |
end | |
class Processing < State | |
def insert_coin | |
return "Sorry! please wait till I finish the current order" | |
end | |
def return_coin | |
return "Order is already done. Cannot return the coin." | |
end | |
def select(beverage) | |
return "Sorry! I'm already processing one order" #vending machine dont have multiprocessors | |
end | |
def get_beverage | |
#make the selected beverage | |
output = machine.processor.dispatch | |
transit_to :ready | |
output | |
end | |
end | |
class Processor | |
include Singleton | |
attr_accessor :available_beverages | |
def beverages_available? | |
!(@available_beverages.nil? or @available_beverages.empty?) | |
end | |
# outputs the beverage after make | |
def dispatch | |
# decrement the amount of the beverage by one | |
@available_beverages[@beverage_processing] -= 1 | |
@available_beverages.delete(@beverage_processing) if (@available_beverages[@beverage_processing] == 0) | |
return "Take your #{@beverage_processing}" | |
end | |
def make(beverage) | |
# processing of beverages goes here | |
# This should return true if the selected beverage can be processed | |
# For simplicity, we just check for the availability of the beverage | |
@available_beverages.include?(beverage) && (@beverage_processing = beverage) | |
end | |
end | |
class VendingMachine | |
attr_accessor :state | |
attr_reader :processor | |
def initialize(beverages={}) | |
@processor = Processor.instance | |
@processor.available_beverages = beverages | |
@state = Ready.new(self) | |
end | |
def method_missing(method, *args) | |
@state.send(method, *args) | |
end | |
end | |
# Normal Process | |
# >> require "new_state_machine" | |
# => true | |
# >> vm = VendingMachine.new {"Tea" => 5, "Coffee" => 10} | |
# => #<VendingMachine:0xb794fff4 @processor=#<Processor:0xb794ffa4 @available_beverages={"Coffee"=>1, "Tea"=>1}, state#<Ready:0xb794ff2c @machine=#<VendingMachine:0xb794fff4 ...> | |
# >> vm.insert_coin | |
# => "Select what do you like to have" | |
# >> vm.select("Coffee") | |
# => "Please wait! Your Coffee will be ready in couple of minutes." | |
# >> vm.get_beverage | |
# => "Take your Coffee" | |
# | |
# Requesting Latte (not available) | |
# >> vm.insert_coin | |
# => "Select what do you like to have" | |
# >> vm.select("Latte") | |
# => "Sorry Latte is not available today" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment