views:

13

answers:

1

Hi all!

Today I was faced with a challenge to create different behaviors for my shopping cart model. That's because the owner of the online shopping wanted to create some promotions like buy 1, get 5 or get 25% discount + some extra stuff, etc...

I thought of doing it with polymorphic inheritance, where my Cart model will only hold the products and accessories bought and will have many "Behavior Models" where it would get its data like the the total of the purchase (that could get 25% off) and call the methods like the one that closes the deal (where i could add new, specified products for the promotions where you get 5 free something).

In the beginning it seemed all right to me to create this kind of relationship as it wouldn't require much work on the model interface as it would continue to communicate normally with other objects, just the internals would be changed. Now i'm seeing myself creating a lot of crap, repeated code over the behavior models and started figuring if there are other, more elegant ways, of doing this...

Do you know a better way?

A: 

I've solved this using a bit of metaprogramming! Now my cart model works like this:

  def after_initialize

    extend BoxStandardMethods

    if self.box_behavior_type?
      extend Object.const_get(box_behavior_type)
    end
  end

where BoxStandardMethods is a module that has all the methods a standard cart has (add_product, remove_product, get_total, etc) and if i want to override any of these methods, i simply set the box_behavior_type attribute of the cart with a module that has the functions i want to override. To avoid incompatibility with the interfaces, i am building the extendable modules with custom fields that are backward-compatible, ie. the standard method add_product(product,amount) is implemented as add_product(product,amount,*custom_data) and if custom_data is nil, then the super method is called, effectively calling the method implemented on BoxStandardMethods

Ruby is simply great for this kind of approach! The system is in production for about a week now and i've had no problems at all!

Lucas d. Prim