Friday, August 03, 2007

Decorator - The Cool Pattern with the Stupid Name

So I have a logging class that is implementation agnostic.  Under the hood it uses an Adapter for Enterprise Library Logging, however we could easily switch it out for log4net if needed without changing the code.

So you can imagine that I have an interface that looks like this:

public interface ILogger

{

    void Write(string text);

    void Warn(string text);

    void Error(string text, Exception msg);

}

… and there is currently an implementation of this class called EntLibLogger:

public class EntLibLogger : ILogger

{       

    public void Write(string text)

    {

        //ent. lib write log entry

    }

 

    public void Warn(string text)

    {

        //ent. lib warn

    }

 

    public void Error(string text, Exception msg)

    {

        //ent. lib error

    }       

}

The specific logger that is used is abstracted behind a factory of course.  However, some of the applications that use this component will not have the logging configuration.  It is perfectly feasible to ignore logging in this scenario (ie: swallow exceptions) however this is something that any logging component would do.  I don’t want to add it to each and every implementation of ILogger.

So here’s where the decorator comes in.  This pattern could really use a better name, but I can’t think of one, so I’ll leave that up to you.

A Decorator implements the same interface, however it wraps each method with its own behavior before deferring the call to an inner implementation.  Wow, that doesn’t really make much sense, so how about an example…

public class SilentlyFailLoggingDecorator : ILogger

{

    private readonly ILogger _innerLogger;

 

    public SilentlyFailLoggingDecorator(ILogger innerLogger)

    {

        _innerLogger = innerLogger;

    }

 

    public void Write(string text)

    {

        try

        {

            _innerLogger.Write(text);

        }

        catch

        {

            //swallow exception

        }

    }

 

    public void Warn(string text)

    {

        try

        {           

            _innerLogger.Warn(text);               

        }

        catch

        {

            //swallow exception           

        }

    }

 

    public void Error(string text, Exception exc)

    {

        try

        {

            _innerLogger.Error(text, exc);

        }

        catch

        {

            //swallow

        }

    }

 

}

All of the actual implementation comes from whatever ILogger is sent via the constructor.  All this class does is “decorate” the method calls with additional behavior.  (This time, we’re choosing to silently ignore errors rather than throw exceptions that cause the program to stop)

To wire this up, wherever the factory method resides that creates the actual logger, you’d write…

public static ILogger GetLogger()

{

    //via IoC or just hard-coding

    return new SilentlyFailLoggingDecorator(

         new EntLibLogger()

    );

}

So there you have it!  The decorator pattern can do all kinds of Aspect-Oriented things such as Log a message each time a method is called, or possibly massage parameters before sending them to an inner class.

Remortgage - Loans - Credit Card Consolidation - Arizona Pools