Opensteam_blog_logo4
opensteam.net | rss | search | archive
Results (escape to close):

State-Pattern using Modules

Posted by michael.schaerfer on 22-Jul-08 at 21:20


In the last weeks, we tried to implement a state-pattern for our orders, simply put: different states means different functionality.
We tried various approaches, like simple state-symbols, state-classes (to hold the state-specifc methods and return new states), state-associations and the very nice AASM plugin by Scott Barron.
But all this techniques felt very clumsy for our simple needs and not so ... 'ruby-like'.

Then i stumbled across Jay Fields Post and really liked the approach of using just state-modules and delegating to the instance_method ('cause all modules included in a class are just ancestors of this class!).

Here a brief overview of our solution:
   1  # the order-class
   2  class Order
   3    include StateLogic
   4  
   5    #states
   6    include Finished
   7    attr_accessor :state
   8  end
The StateLogic Module (defines the 'fire_event' method to delegate to the state-module).
   1  module StateLogic
   2    def fire_event(name, *args, &block)
   3      state_module = self.state.classify.constantize
   4      
   5      if state_module.instance_methods(false).include?(name)
   6        state_module.instance_method(m).bind( self ).call( *args, &block )
   7      else
   8        puts "event '#{name}' not defined for state '#{state}'"
   9        return false
  10      end
  11    end
  12  end
A State-Module
   1  module Finished
   2    def self.included(base)
   3      self.instance_methods(false).each do |m|
   4        base.class_eval do
   5          define_method(m) { |*args| fire_event(m,*args) }
   6        end
   7      end
   8    end
   9  
  10    #an event
  11    def say_something
  12      puts "now in state '#{state}'"
  13    end
  14  
  15  end    
As you can see, we override every state-module instance_method in the receiver-class to call the fire_event method. And in this method, we check if the current state-module defines such an instance_method, bind it to the order-instance and call it (or printing an error message, if no such method is defined in the current state-module.)
Pretty simple!

Tags: code, release
Hierarchy: previous, next

Comments

There are 0 comments on this post. Post yours →

Post a comment

Required fields in bold.