Configurar decoradores en Castle Windsor

El patrón decorador es uno de mis favoritos porque, en mi opinión, permite añadir funcionalidad a un sistema de una forma muy sencilla. Si además contamos con algún tipo de contenedor de inversión de control, podemos añadir esa funcionalidad de una manera muy limpia y aséptica, sin tocar el código que ya existe y acercándonos al ideal del OCP.

Suelo utilizar Castle Windsor como contenedor de inversión de control en mis aplicaciones, y aunque me costó encontrarla, existe una forma idiomática de configurar cadenas de decoradores en Windsor.

Supongamos que tenemos una serie de servicios definidos así:

public interface IService 
{
    void DoSomething();
}

public class Service : IMyService
{
    public void DoSomething()
    {
        // ...
    }
}

public class SecurityDecorator : IMyService
{
    private readonly IService inner;

    public SecurityDecorator(IService inner)
    {
        this.inner = inner;
    }

    public void DoSomething()
    {
        // Validar que se puede ejecutar la acción
        // ...
        // Delegar en el servicio que estamos decorando
        inner.DoSomething();
    }
}

public class AuditDecorator : IMyService
{
    private readonly IService inner;

    public AuditDecorator(IService inner)
    {
        this.inner = inner;
    }

    public void DoSomething()
    {
        // Delegar en el servicio que estamos decorando
        inner.DoSomething();
        // Auditar la acción
        // ...
    }
}

Si queremos registrarlos para que SecurityService sea un decorador de AuditService y que éste, a su vez, decore al Service real, bastaría con hacer lo siguiente:

var container = new WindsorContainer();
container.Register(
    Component.For<IService>().ImplementedBy<SecurityDecorator>(),
    Component.For<IService>().ImplementedBy<AuditDecorator>(),
    Component.For<IService>().ImplementedBy<Service>());

Lo que hace Windsor a la hora de resolver los componentes, es buscar las implementaciones de las dependencias de cada componente, pero en ese proceso tiene en cuenta cual es el componente que estamos resolviendo y lo saca de la lista de candidatos posibles para satisfacer la dependencia para evitar entrar en un bucle infinito.

De esta forma, con el registro que aparece arriba, cuando le pedimos a Windsor resolver un IService, devuelve el primer componente registrado (que es el componente por defecto, al menos hasta Winsor 3.0). Para construir un SecurityDecorator, Windsor necesita una instancia de IService, puesto que SecurityDecorator recibe un parámetro de ese tipo en el contructor (inner). Para crear ese IService, Windsor busca la siguiente clase que esté registrada como IService. Por tanto, Windsor selecciona AuditDecorator para satisfacer la dependencia sobre IService de SecurityDecorator. Cuando Windsor va a instanciar AuditDecorator… bueno, ya se ve claro lo que pasa.

Lo mejor de esta forma de registrar decoradores es que queda muy claro el orden en que se ejecutan y quién decora a quién. Además, el que sea tan fácil crear la cadena de decoradores ayuda a emplear más este patrón que, en muchas ocasiones, ayuda enormemente a simplificar el diseño y evitar saturar una clase con demasiadas responsabilidades.

2 comentarios en “Configurar decoradores en Castle Windsor

  1. Pingback: Modificar una clase en Javascript: Eliminar los markers de Google Maps « Koalite's blog

  2. Pingback: AOP con Castle Windsor: IInterceptor « Koalite's blog

Comentarios cerrados.