Conectando las piezas

Como dijimos en un post anterior, para lograr un bajo acoplamiento hacemos referencia a contratos (interfaces) y no a implementaciones (clases), pero cuando queremos ejecutar nuestra aplicación (o parte de ella) necesitamos hacer uso de las implementaciones. Y qué mejor que delegar el control de creación de objetos en algún framework especializado para tal fin. ver Inversion of Control (IoC) y Dependency Injection (DI)

En nuestro ejemplo usamos Castle Windsor, pero podría ser Sprint.NET, Unity, LinFu, etc. y hasta sería interesante abstraernos de quien sea nuestro IoC / DI, y para esto contamos con Common Service Locator.


La idea de todo esto es poder solicitar un determinado objeto, por ejemplo un Model, y que ya tenga sus referencias a otros objetos inyectadas, como por ejemplo los DAOs que necesita.

¿Cómo hacemos este "cableado" con Castle?

 ver documentación completa

Para declarar un componente:

<component id="IInvoiceDAO"
           service="DMS.DAOs.IInvoiceDAO, DMS.DAOs"
           type="DMS.DAOs.NH.InvoiceDAO, DMS.DAOs.NH"
           lifestyle="singleton">
</component>

donde id es la identificación del componente tanto para referencias internas en el archivo de configuración como para solicitarlo desde nuestra aplicación, service es el contrato que debe cumplir y type es la implementación que deseamos usar.

y para interconectar componentes: 

        <component id="IInvoiceViewModel"
                       service="DMS.Models.IInvoiceViewModel, DMS.Models"
                       type="DMS.Models.Impl.InvoiceViewModel, DMS.Models.Impl">
            <
parameters>
                <
InvoiceDAO>${IInvoiceDAO}</InvoiceDAO>
            </
parameters>
        </
component>

donde parameters son la lista de parámetros del constructor de InvoiceViewModel o propiedades púbicas de este. En este caso estamos inyectando el componente definido como IInvoiceDAO.

Nota: si tenemos un único componente del tipo del parámetro, Castle lo va a inyectar sin necesidad de que se lo especifiquemos. es decir, que en este ejemplo no sería necesario indicar el parámetro.

Otra forma de configurar el container

También podemos configurar Castle Windsor mediante Fluent Registration API de la siguiente manera:

IWindsorContainer container = new WindsorContainer()
.AddFacility("factory.support", new FactorySupportFacility())
.Register(Component.For<MockHelper>()
.ImplementedBy<MockHelper>())
.Register(Component.For<IInvoiceDAO>()
.UsingFactoryMethod(kernel => kernel.Resolve<MockHelper>().CreateInvoiceDAO())
.LifeStyle.Singleton)
.Register(Component.For<IInvoiceViewModel>()
.ImplementedBy<InvoiceViewModel>()
.LifeStyle.Transient);

Como podemos ver, en esta configuración no estamos especificando los parámetros, como dijimos antes en Nota, no es necesario especificarlo en este caso.

Usando CommonServiceLocator

Finalmente, para abstraernos de la implementación del IoC container, podemos crear un ServiceLocator pasándole como parámetro el container ya configurado:

IServiceLocator serviceLocator = new WindsorServiceLocator(container);

y luego nos referiremos a este de la siguiente forma:

IInvoiceViewModel model = serviceLocator.GetInstance<IInvoiceViewModel>();

Descargar el código fuente completo

1 comentario:

  1. Nelo!!!
    Buenísimo el blog che, te felicito.
    Lo voy a seguir...
    Un abrazo
    el pollo (era bt)

    ResponderBorrar