Tuesday, May 23, 2006

Law of Demeter and Forwardable

While developing software I often see Law of Demeter violations. These days I seem to see more of this, probably because Ruby on Rails allows you to easily navigate between objects based on table relationships. For example, if you are working on a partial that displays a charge from a credit card statement it wouldn't be surprising to see:
charge.statement.customer.name
The above code could be used to display the customer's name in the partial. Unfortunately, it assumes statement will have a customer and customer will have a name. This is easily fixed by changing charge to only talk to it's friends.
charge.customer_name
The simple fix to support this is to define customer_name in charge, and customer_name in statement
class Charge
def customer_name
statement.customer_name
end
end

class Statement
def customer_name
customer.name
end
end
This change is simple enough; however, as the list of methods that require delegation grows your class can become littered with delegation code.

Luckily, Forwardable is included in the standard library. Forwardable allows you delegate method calls to an object, on a method by method basis. Using Forwardable the above code becomes:
class Charge
extend Forwardable
def_delegators :statement, :customer_name
end

class Statement
extend Forwardable
def_delegator :customer, :name, :customer_name
end
Forwardable becomes even more valuable when you need to delegate several methods
def_delegators :amount_info, :units, :fractions, :currency
For more info on Law of Demeter and it's advantages check out the definition on Wikipedia. For more info on Forwardable check out the documentation on Ruby-Doc.
Post a Comment