Self-conscious Decoration
February 12th, 2007 by michael
Variations on the Decorator Design Pattern in Ruby have already been discussed in several places. For my special purpose, none of these approaches works.
The common problem with a decorator based on delegation is the lost sense of self. Method calls of the decorated object to itself are not routed through the decorator, therefore remain woefully undecorated.
The Ruby idiom of aliasing and redefining methods, in effect adding around advice, is possible, when the decoration applies to all uses of the “core” class. It is not suitable when you need decorated as well as undecorated variants.
There’s an almost classical: Just derive a subclass from the “core” class and add the decoration in there. Doing this explicitly is tedious, ugly, and multiplies classes semper necessitatem. Luckily, for us and poor, overquoted Father Ockham, Ruby is a highly dynamic language where things are possible that users of other languages can only dream of (longingly or in nightmares, that’s quite a different issue).
So, without further ado, here’s a simple demonstration of the technique.
class Core
def m1
puts "Core#m1"
end
def m2
puts "Core#m2"
m3
end
def m3
puts "Core#m3"
end
def m4
puts "Core#m4"
end
end
class Decorator
class << self
def new(*args)
decorate(Core).new(*args)
end
private
def decorate(klass)
decorated_class = Class.new(klass)
decorated_class.send(:include, Decoration)
decorated_class
end
end
module Decoration
def m1
puts "Decorator#m1"
super
end
def m2
puts "Decorator#m2"
super
end
def m3
puts "Decorator#m3"
super
end
end
end
With that under under our collective belt, here’s the case that motivated my attempt at self-conscious delegation. In a Rails application, I have several layers of FormBuilders. At the base, derived from ActionView::Helpers::FormBuilder is a form builder that provides mechanisms. For example for adding labels to input elements and for automatically displaying appropriate widgets for various association types. On top of that, I have two form builders that add layout specifics; one for CSS-based layouts, one for table-based layouts. I still need a further layer for policy: only show users what they are allowed to see and touch. This last policy layer is, of course, independent of layout (and vice versa!), therefore, short of full-fledged AOP, decoration was the way to go.
class DecoFormBuilder
class << self
def new(object_name, object, template, options, proc)
delegate_class = options.delete(:delegate_builder)
raise ArgumentError, 'No :delegate_builder given to DecoFormBuilder' unless delegate_class
decorate(delegate_class).new(object_name, object, template, options, proc)
end
private
def decorate(klass)
decorated = Class.new(klass)
decorated.send(:include, Decoration)
decorated
end
end
module Decoration
def initialize(object_name, object, template, option, proc)
super
# Do whatever initialization you need here
end
# Put the decorating methods here and don't forget to
# call super.
end
end

Hello Michael, it’s funny how at the same time both of us faced the problem of handling large record sets with active record, and focused on creating a decorator that had a way to be a “complete” and “invisible” shell to the decorated object.
But, thanks to the expressiveness of Ruby, we came to different implementations: I used a blank class, an invisible slate that wraps the original class. http://pastie.caboo.se/39504
The first drawback is that Kernel#send will invalidate any protected/private access modifier, but send will behave like a method call in 1.9 so why should backport it to 1.8?
)
Hope that you enjoy it!
marcello
Marcello, if I’m not mistaken your approach does not solve my fundamental problem with delegation, i.e., that self refers to the “wrong” (inner) object and so methods called from there on itself are not decorated.
michael, you’re right. but I don’t think there’s an agile way of implementing this kind of decoration, or maybe this could be a starting point (untested and written here)
require ‘active_support’
module Deco
def self.included(base)
blank = Proc.new {}
base.instance_methods.each { |m|
alias_method_chain m, :with_decoration
define_method(“#{m}_with_decoration”, &blank)
}
end
end
module MyDecoration
def old_method_with_decoration
# do something
old_method_without_decoration
end
end
klass.extend Deco
klass.extend MyDecoration
but surely there are better ways..
Marcello, the approach I demonstrate in the article already handles this. That was the entire point. Try the code and you’ll see it.
Michael, I like what you’ve done here. To help me understand better including the Decorator Pattern, as an exercise I modified your Decorator class so I could subclass it and be DRY with the new and private decorate methods. I wonder if you could comment on what I’ve done.
The idea is that I could have multiple ‘Decorators’ each with its own set of methods but make use of the generic aspects of the Decorator itself (this is just a minor addition and doesn’t have much to do with the concept you are showing but might be useful to others). Decorator can be used generically to assist in wrapping any class.
I show only my ‘SpecialDecorator’. I also show these separated into individual files.
deco_core.rb (your Core equiv with just 2 methods)
class DecoCore
def m1(message)
puts “DecoCore#m1 ” + message
end
def m2(message)
puts “DecoCore#m2 ” + message
end
end
decorator.rb (your Decorator modified to be a superclass)
class Decorator
class
My comment was too long…here’s some more:
decorator.rb
class Decorator
class
Don, I have to admit that I don’t quite understand what you’re trying to do.
Michael, unfortunately my comment was too long and was cut short. If you’d like I can email my code to you. I’d really appreciate your comments. If it has value you are welcome to use it to add to your posting.
In short, I want to have a Decorator class that I can reuse to do the work of wrapping other classes. Then I want Decorator subclasses that provide the methods (what you send to the decorated class). They make use of the class being wrapped as well as provide their own unique logic. I think that’s the idea of the Decorator Pattern. These are in separate files because I might have lots of them.
Beyond that I was just experimenting with your ideas and getting a similar example working that incorporated my ideas. I wanted to know if what I was doing made sense to you and if you could give me some pointers to help clarify my understanding of Decorators and what you are trying to accomplish.
Email me if you’d like the code I have.
Thanks Don
Don, I see your point. However, instead of a homebrew solution that implements part of aspect-oriented programming, you might want to have a look at a full solution such as Aquarium.