Speaking to a colleague about the Decorator pattern, I think I was unduly harsh on decorators the last time I wrote on the subject. I’ll start off by re-iterating my opinion that writing pass-through methods is for the most part a horrible waste of time and a code smell to boot. However, there are some cases where proxy/decorator functionality is useful where there are relatively few methods you need to proxy. Ironically, one of these is my very first post. It employs the decorator pattern to give you a class that executes Retlang Commands, but allows you to halt processing at a time of your choosing. This kind of buffering is generally useful, you can do things like process a message based on the following message this way (and if you know enough about Bloomberg feeds, you’ll know why this isn’t an academic example).
Some other examples of where the decorator pattern can come in handy:
- Currency Conversion: here the converted amount can be a decorator on the underlying value.
- A read-through cache: here the read-through functionality is added as a decorator on the underlying value.
- Parameter interception: mostly useful for testing, you log the parameters and then call through to an underlying implementation. (I actually used to have a Rhino Mocks capture constraint that was a decorator around a proper constraint.)
A good rule of thumb for using the decorator pattern:
- You have an underlying behaviour that you wish to leverage. In the case of the haltable executor, I wanted to allow any underlying executor.
- You want to change one particular aspect of the underlying behaviour. Again, in the case of the haltable executor, I wanted to allow for halting.
- There are very few methods that need delegating.
Decorator vs Composite
The problem with decorator is that you’re constantly in danger of making a Law of Demeter violation. You’ve got to ask yourself “do I really need the underlying object, or is it just convenient?” Let’s take the example of the Rhino Mocks capture constraint. In practice, I didn’t really have any underlying behaviour I wished to leverage. I just wanted to deal with the fact that you can only have one constraint per parameter. Problem is, we’ve already got a pattern for dealing with that situation: composite. A proxy or decorator needs exactly one target.
Now imagine you can a constraint that evaluated both constraints (it’s not hard, it actually exists: Rhino.Mocks.Constraints.And). Now you can have the capture constraint just always return true. Your constraint now becomes “the underlying constraint” and “the capture constraint”.
Decorator vs Chain of Responsibility
Some have argued that Chain of Responsibility, one of my personal favourite patterns, should be replaced wholesale with Decorator. I seriously disagree with this. First, let me point out that the version I used in the previous post on the subject isn’t actually the classic gang of four pattern. The original is a linked list, hence the “Chain” terminology. The interface I gave has rules that don’t need to know about other rules. This gives you a bit more flexibility in constructing different rule chains. Providing the rules don’t need to share information (which will usually cause problems of their own) linked-list behaviour or using a decorator is just a Law of Demeter violation.