Codebrahma

Work

Ruby Decorators: Add behavior to objects

Let us consider a problem in which we have a Car class. The top speed of any car is a maximum of 100kmph but by adding extra power packs to the car we can increase the speed of the car. These packs are Nitro and Boost. Nitro increases the speed of the car by 30kmph and Boost increases it by 50kmph. Also a car can add any number of these utilities to reach super high speeds.

Solving using Inheritance

class Car
  def top_speed
    100 
  end 
end 

class CarWithNitro < Car 
  def top_speed
    super + 30 
  end 
end
  
class CarWithBoost < Car 
  def top_speed 
    super + 50 
  end 
end 

The drawback of this pattern is The Ruby Decoratorssubclasses are tightly coupled to the super class. Suppose if the we change the name of the method in the super class we need to make these changes to our subclasses as well. No way of adding any packs to a car dynamically. If in a certain scenario we need a car with two nitro packs and three boost packs it's not easy with this architecture.

Enter the decorator pattern

The decorator pattern allows you to attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

  • A decorator is a wrapper object on the component class.
  • Has the same interface as the component it is decorating so that it's presence is transparent to the clients
  • Delegates requests to components
  • Performs additional actions before or after delegating

Applying decorator pattern to our problem step by step

  • The component class that we would want to add new features to or "Decorate" is "Car"
  • The decorators would be in this case "Nitro" and "Boost"

Now that we have identified what decorators we need let's write it

class Nitro
  # Wrapping the component class, Car object in this case 
  def initialize(component)
    @component = component
  end 
    
  # maintain the same public interface as component
  def top_speed 
    # after delegation modify the value 
    @component.top_speed + 30
  end
end
  
class Boost
  def initialize(component)
    @component = component
  end
    
  def top_speed
    @component.top_speed + 50
  end
end 

Now we can start using our decorators to add new packs to a car object.

Nitro.new(Car.new).top_speed #130 

Nitro.new(Nitro.new(Car.new)).top_speed #160 

Boost.new(Nitro.new(Car.new)).top_speed #180

That's it, our shiny new power packed cars are ready to be driven 😉

Written by
Abhishek Sarkar
Published at
Apr 28, 2014
Posted in
Development
Tags
If you want to get more posts like this, join our newsletter

Join our NEW newsletter to learn about the latest trends in the fast changing front end atmosphere

Mail hello@codebrahma.com

Phone +1 484 506 0634

Codebrahma is an independent company. Mentioned brands and companies are trademarked brands.
© 2021 codebrahma.com. All rights reserved.