Jan 18 2013

Creating View-Centric Interfaces with the Decorator Pattern

Occasionally in the life-cycle of an application we find that we need two distinct domain objects to quack alike, even if their underlying structures differ greatly. Moreover, often the second, third and thirty-ninth such objects come long after the initital object entered the application. One approach would be to shove all of the necessary functionality into the original object and add a ”type” flag of some sort. Another would be to use single table inheritance or even multiple table inheritance (here’s a gem) if we’re feeling fancy. Another approach is to decorate the objects identically so they all quack like the round-duck-in-the-square-hole you want them to be.

Consider some Widget class, persisted through ActiveRecord, with a couple of attributes and a virtual attribute:

class Widget < ActiveRecord::Base
  attr_accessible :name, :feature

  def display_title
    "Hi my name is #{name} and I can do #{feature}"
  end
end

along with, for instance, some view template for the show action (here presented in Slim):

h1 Widget!
p
  ' Name:
  = @widget.display_title

While this may not be an optimal starting place, its simplicity makes it a great place to start. If more flexibility isn’t demanded at this point, why would you introduce decorators? At least the display logic in the view is isolated to a single method. Later, if things start to get out of control, extraction of #display_title to a more appropriate home should be simple enough.

Several iterations later…

Say that after launch, and during the course of new feature development, a new business need arises. Our previously flimsy Widgets have a more musically inclined MetalWidget cousin that must come into play. These new loud, rock-themed widgets need to be displayed in exactly the same way as their humbler cousins, but with different underlying attributes. One option would be to put some business logic in the view and render a different partial depending on the Widget type. Another option would be to leverage the Decorator pattern and build decorator classes to wrap up the two objects with a consistent interface. The first step in such a refactor is to simply extract the Widget display logic from the view into a decorator of some type. In the following examples we will use Draper, but any implementation of the decorator or presenter pattern should work. We can move the Widget#display_title method into a decorator, remove it from the model and update the WidgetsController show action to decorate the Widgets before rendering the view.

class ApplicationDecorator < Draper::Base
end

class WidgetDecorator < ApplicationDecorator
  decorates :widget

  def display_title
    "Hi my name is #{name} and I can do #{feature}"
  end
end

Then we can introduce the MetalWidget class in order to make the application significantly louder.

class MetalWidget < ActiveRecord::Base
  attr_accessor :band_name, :number_of_demo_tapes
end

In order to render these new leather-clad Widgets, we need to give them a decorator as well, so that they can be displayed in the same show action.

class MetalWidgetDecorator < ApplicationDecorator
  decorates :metal_widget

  def display_title
    <<-BAND_STUFF
    We are #{band_name}! Thanks for coming. Please pick up one of our
    #{number_of_demo_tapes} excellent early albums from the site before
    you go!
    BAND_STUFF
  end
end

So now instances of either Widget or MetalWidget can be displayed equally well with a single template. Another benefit of this refactoring is that the two Widget classes actually look very similar. The virtual attribute has been pulled out so the original Widget is smaller and more focused, and display concerns live elsewhere. Taking this idea further, it can be handy to create a common ancestor for all Widget decorators so that a given Widget type will never blow up in a view, even if it doesn’t implement the entire interface needed by the view. For example, we might have:

class WidgetDecorator < ApplicationDecorator
  def display_title
    ""
  end
end

class WidgetDecorator < WidgetDecorator
  decorates :widget
  def display_title
    #...
  end
end

class MetalWidgetDecorator < WidgetDecorator
  decorates :metal_widget
  def display_title
    #...
  end
end

This final step is similar to a Null Object pattern, in that it prevents views from raising exceptions if unknown methods are called. We could bring other machinery to bear here, but this feels pretty natural in the course of refactors such as the above.

With this process, and leveraging the power of inheritance, we are able to create a family of objects that all quack alike and allow us to iteratively implement the view concerns of new, but related, domain objects as they are introduced to the system. The base class of the inheritance hierarchy allows us to have reasonable default behavior, which may simply be doing nothing except not throwing an exception, and inheriting decorators can override that behavior to provide correct information to the views.

How do you build flexibility into your domain models? Do you replace conditionals with polymorphism or extract service objects, or do you have another preferred method?

No Comments

Leave a Comment

Join the discussion. Do not worry, your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>