Articles Feed

Authors

Categories

Understanding Statemachines, Part 3: Conditional Logic

by: micah | February 12th, 2007 |

Conditions

If you’re doing any significant amount of work with statmachines, you will most certainly encounter some conditional logic in your statemachines. Take our vending machine. When ever a coin is inserted, the invoked event will depend on whether the total amount of money inserted is sufficient to buy something. If enough money has been tendered, the display should suggest that the customer make a selection. If insufficient money has been inserted, the customer should be prompted to insert more.

Conditional logic can be accomplished by using entry actions. See the diagram below.


State Diagram with Conditional Logic

Starting in the Accept Money state, when a coin is inserted, the coin event is fired and the statemachine transitions into the Coin Inserted state. This is where it gets fun. Upon entering of the Coin Inserted state its entry event is invoked: count_amount_tendered. This method will count the money and invoke the not_paid_yet or paid event accordingly. This will cause the statemachine to transition into the appropriate state.

The Coin Inserted state is unique. You wouldn’t expect to find the statemachine in the Coin Inserted state for any reason except to make this decision. Once the decision is made, the state changes. States like this are called Decision States.

Code

  1. require 'rubygems'
  2. require 'statemachine'
  3. class VendingMachineContext
  4. attr_accessor :statemachine
  5. def initialize
  6. @amount_tendered = 0
  7. end
  8. def add_coin
  9. @amount_tendered = @amount_tendered + 25
  10. end
  11. def count_amount_tendered
  12. if @amount_tendered >= 100
  13. @statemachine.paid
  14. else
  15. @statemachine.not_paid_yet
  16. end
  17. end
  18. def prompt_money
  19. puts "$.#{@amount_tendered}: more money please"
  20. end
  21. def prompt_selection
  22. puts "please make a selection"
  23. end
  24. end
  25. vending_machine = Statemachine.build do
  26. trans :accept_money, :coin, :coin_inserted, :add_coin
  27. state :coin_inserted do
  28. event :not_paid_yet, :accept_money, :prompt_money
  29. event :paid, :await_selection, :prompt_selection
  30. on_entry :count_amount_tendered
  31. end
  32. context VendingMachineContext.new
  33. end
  34. vending_machine.context.statemachine = vending_machine
  35. vending_machine.coin
  36. vending_machine.coin
  37. vending_machine.coin
  38. vending_machine.coin

Output:

$.25: more money please $.50: more money please $.75: more money please please make a selection

Next lesson: Superstates
Understanding Statemachines, Part 4: Superstates

Leave a Reply

#