Friday, January 15, 2010

10 Advanced Windsor Tricks – 4. How to register and use decorators

Here’s part four of (at least) 10 Advanced Windsor Tricks.

The decorator pattern is an old friend from the Gang of Four book and goes back to the earliest days of Object Oriented programming. It’s a very simple but powerful idea. Let’s remember our old friend ThingOne:

public class ThingOne : IThing
{
    public string SayHello(string name)
    {
        return string.Format("ThingOne says hello to {0}", name);
    }
}

A decorator is a class that both implements an interface and has a reference to it. This is so that it can pretend to be something else and intercept any calls made to the wrapped instance. Here’s an IThing decorator:

public class ThingDecorator : IThing
{
    private readonly IThing thing;

    public ThingDecorator(IThing thing)
    {
        this.thing = thing;
    }

    public string SayHello(string name)
    {
        Console.WriteLine("Before calling wrapped IThing");
        var message = thing.SayHello(name);
        Console.WriteLine("After calling wrapped IThing");
        return message;
    }
}

A decorator can do anything it likes before and after the call to the wrapped class including altering its arguments and/or return value. There is much discussion of AOP these days and heavyweight frameworks like PostSharp; indeed Windsor itself is an excellent AOP framework; but often a decorator is a much simpler solution to these kinds of interception requirements. Don’t get me wrong though, I think PostSharp is the bees knees :)

Now we can compose the decorator with the target and allow the decorator to intercept calls to the target:

var thing = new ThingDecorator(new ThingOne());
Console.WriteLine(thing.SayHello("Roger"));

Which will print out:

Before calling wrapped IThing
After calling wrapped IThing
ThingOne says hello to Roger

Windsor makes working with decorators a breeze. You don’t have to explicitly wire up the decorator with a service override, simply order the registrations with the outermost decorator first and Windsor will magically wire them up for you. So to register ThingDecorator and ThingOne just do the following:

var container = new WindsorContainer()
    .Register(
        Component.For<IThing>().ImplementedBy<ThingDecorator>(),
        Component.For<IThing>().ImplementedBy<ThingOne>()
    );

var thing = container.Resolve<IThing>();

Console.WriteLine(thing.SayHello("Roger"));

This prints out the same result as the code above.

Now, let’s introduce a second decorator:

public class ThingDecorator2 : IThing
{
    private readonly IThing thing;

    public ThingDecorator2(IThing thing)
    {
        this.thing = thing;
    }

    public string SayHello(string name)
    {
        return thing.SayHello(name + " has been altered by ThingDecorator2... ha ha ha!");
    }
}

When we register this decorator as well we get just the effect we expect:

public void decorator_should_work_without_any_special_registration()
{
    var container = new WindsorContainer()
        .Register(
            Component.For<IThing>().ImplementedBy<ThingDecorator>(),
            Component.For<IThing>().ImplementedBy<ThingDecorator2>(),
            Component.For<IThing>().ImplementedBy<ThingOne>()
        );

    var thing = container.Resolve<IThing>();

    Console.WriteLine(thing.SayHello("Roger"));
}

This prints out:

Before calling wrapped IThing
After calling wrapped IThing
ThingOne says hello to Roger has been altered by ThingDecorator2... ha ha ha!

It’s nice, in fact it’s cooler than a Shaft and Fonz love child :)

9 comments:

KnightRider said...

Instead of doing the following to configure the decorators:

var container = new WindsorContainer()
.Register(
Component.For().ImplementedBy(),
Component.For().ImplementedBy(),
Component.For().ImplementedBy()
);

Can I create the same type of chain in windsor's XML configuration so I can add and remove decorators by simply changing the config file?

thanks

Mike Hadlow said...

KnightRider, yes you can :)

KnightRider said...

Any direction/link you can provide to show how to do it in config?

I plan to use caching and logging between my UI and service layer and between my service layer and repository and would like to easily be able to plug them in and pull them out via config.

thanks

Mike Hadlow said...

This is the equivalent of the fluent registration above:

<configuration>
<components>
<component service="My.Project.IThing" type="My.Project.ThingDecorator" />
<component service="My.Project.IThing" type="My.Project.ThingDecorator2" />
<component service="My.Project.IThing" type="My.Project.ThingOne" />
</components>
</configuration>

KnightRider said...

Ok, so it just builds the decorator wrappers in the order they appear in the config file.

So ThingOne is wrapped by ThingDecorator2 which is wrapped by ThingDecorator. So what I call ServiceLocator.GetService[IThing]), I'll get back an object who's "outermost" object is a ThingDecorator.

Thanks Mike! Previously I was using named services and calling them in the order I wanted by name, and that was smelly, sticky, and all kinds of bad. :)

Anonymous said...

I've got a storedProcedureSelect decorating storedProcedureBase and storedProcedureUpdate decorating storedProcedureBase aswell but I do not want storedProcedureUpdate to wrap storedProcedureSelect. How do I do two decorator registrations that are independent from each other?

Anonymous said...

There's good reason against mixing component registration and decorator configuration. Service overrides define which imlementation is used by a component that needs it. Registration order defines a default implementation for a service, which is a rather different concern. A working example, though.

sankar_gorantla said...

Hi I want to resolve my interface automatically with out calling that resolve method.

Is there any way to do that ?

Please help me....

Anonymous said...

very nice and funny ;)