Sunday, August 10, 2008

Extension methods as a new Fluent Decorator Pattern?

So recently I have been on this kick to learn Design Patterns in Ruby, and to figure out all kinds of neat ways to do the same design patterns in a dynamic language that is as versatile and elegant as Ruby. While playing around with the decorator pattern in Ruby, I started trying to think of slick ways to accomplish the pattern in C# 3.0.

In Ruby, there is a really slick (and somewhat dangerous) way to handle the means to accomplish the decorator pattern in Ruby (hold on guys, I am getting to the C# part in a bit, I am trying to explain how I got there):

Imagine a string class that holds a string with a method called “write_line”. Suppose for some reason you wanted to apply a decorator pattern to this, and decorate the string at runtime to make the string perform in various output ways. In Ruby, you could tackle it the GoF (Gang of Four) ways, or you could do the following:

Alias method Wrapper:

Decorate with Modules:

Ok, so since Ruby is so dynamic, it can on the fly edit the class instance and inject objects in the inheritance chain after the class itself. So you can utilize this to decorate your base functionality at runtime.

However, C#, since it is statically typed, really won’t allow you to tackle it this way. I started thinking about some of the new features in C# 3.0, and some of the things I have read about, and some of the things I have played around with using Piping, Filtering, and a Fluent Interface (I first started learning about this on the MVC Storefront series by Rob Connery [I highly recommend watching this series btw]). It occurred to me, that although we can’t accomplish the decorator pattern the Ruby way, we can accomplish it a nice readable way using Piping and a Fluent Interface way.

Take for example the standard Decorator Pattern typically seen in C# (using the above example in the classic GoF way):

var outputString = new List<string>{“hello”, “world”, “this”, “is a”, “test”};
var myDecoratedString = new NumberingString(new TimeStampString(new SimpleString()));


The above would use the chain of sequences called by Write to build out the string that is Timestamped, Numbered, and outputted.

This is fine and dandy, but not very pretty to look at in the least. And since the Decorator Pattern, is basically hiding the base object (that does the real work) in itself, it is simply chaining it out till it gets to the base object (“chaining” being the operative word here – similar to Piping).

So what if we do this in a fluent type of way?

var outputString = new List<string>{“hello”, “world”, “this”, “is a”, “test”};
var myDecoratedString = new SimpleString().WithNumbering().WithTimeStamp();
myDecoratedString.Write (outputString);

This is much more readable if you ask me, and it is very clear and concise into what is happening. It is saying that you want a SimpleString object that has Timestamp and Numbering to decorate it.

The Decorator objects have been transformed into extension methods that act on the SimpleString object and decorate it from the extension method.

A simple example of this would be the following:

1 2


Output would be the following:


Now I am fully aware this is only decorating one function on the concrete component. But there is no reason you couldn’t make the Class Decorator (in this example the SimpleClassDecorator) have multiple Action<T> (or Action<T, S> …, or even Func<T, TResult> if you need return values).

In most cases however, there is mostly one entry point into making a class start doing something. Keep in mind, while the SimpleClassDecorator class may look somewhat ugly (because you are encapsulating the block in a delegate), it pays off when you call your decorators. And you only have to write one SimpleClassDecorator, but you can write tons of Decorating Extension Methods to decorate your concrete component object, that actually look quite easy to make going forward.

Anyways, this certainly isn’t the only way to do a Fluent Decorating Pattern, but it was my first attempt at 2am in the morning (I hate it when I think of something in the middle of the night and need to figure it out).

Also, it’s worth noting that this would also be trivial to do the same thing in Ruby, just using blocks.

kick it on

No comments: