El blog del burgués

21 febrero 2011

Inyección de dependencias

Filed under: C#,CAB,SCSF — elburgues @ 8:04 PM

La inyección de dependencias es cuando una clase principal hace uso de una clase secundaria sin hacer referencia directa a ella. Alguna entidad externa proveerá la clase secundaria a la clase principal en tiempo de ejecución, inyectará la dependencia. Para ser útil, la clase secundaria deberá implementar una interfaz que la clase principal conocerá. El objetivo de esto es permitir cambiar el comportamiento de nuestra estructura de clases, cambiar que clase secundaria es inyectada a la clase principal. Como la clase principal no tiene una dependencia directa con ninguna clase secundaria, esto puede ser decidido en tiempo de ejecución. Esta es precisamente la diferencia entre la inyección de dependencias y el patrón strategy. De esta manera, el código se vuelve flexible, desacoplado y fácil de modificar.
No es una buena idea utilizar el archivo de configuración de una aplicación para modificar el comportamiento de la misma,pero lo utilizaremos en el siguiente ejemplo para poder entender el concepto de inyección de dependencias. Los frameworks de inyección de dependencias en general permitirán especificar inyecciones a través del código fuente. Veamos el siguiente diagrama de clases:

La clase principal contiene una referencia a un objeto que implementa IClaseDependiente y así poder llamar al método HacerAlgo de un objeto. ClaseDependiente1, ClaseDependiente2 y ClaseDependiente3 implementan esa interfaz. Un código cliente entonces creará la apropiada dependencia y le dirá a la clase principal que lo use (via la interfaz). Es fácil de entender si vemos el código fuente:

using System;

namespace InyeccionDependencias
{
    class Program
    {
        static void Main(string[] args)
        {
            IClaseDependiente dependencia = ObtenerDependencia();

            ClasePrincipal clasePrincipal = new ClasePrincipal();

            // Aquí es donde inyectamos la dependencia
            clasePrincipal.ClaseDependiente = dependencia;

            clasePrincipal.HacerAlgo();

            Console.ReadLine();
        }

        /// <summary>
        /// Aqui es donde obtenemos la dependencia correspondiente
        /// a lo que ponga en el fichero de configuración de la aplicación.
        /// </summary>
        /// <returns></returns>
        static IClaseDependiente ObtenerDependencia()
        {
            string claseACrear = Properties.Settings.Default.NombreClase;
            Type tipo = System.Type.GetType(claseACrear);
            IClaseDependiente dependencia = (IClaseDependiente)Activator.CreateInstance(tipo);
            return dependencia;
        }
    }

    public interface IClaseDependiente
    {
        void HacerAlgo();
    }

    public class ClaseDependiente1 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 1");
        }
    }

    public class ClaseDependiente2 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 2");
        }
    }

    public class ClaseDependiente3 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 3");
        }
    }

    /// <summary>
    /// La clase principal no tiene conocimiento alguno acerca de las clases secundarias,
    /// solamente de su funcionalidad, a través de la interfaz.
    /// </summary>
    public class ClasePrincipal
    {
        IClaseDependiente claseDependiente;

        public IClaseDependiente ClaseDependiente
        {
            get
            {
                return claseDependiente;
            }
            set
            {
                claseDependiente = value;
            }
        }

        public void HacerAlgo()
        {
            claseDependiente.HacerAlgo();
        }
    }
}

El fichero App.Config sería como sigue:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="InyeccionDependencias.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <applicationSettings>
        <InyeccionDependencias.Properties.Settings>
            <setting name="NombreClase" serializeAs="String">
                <value>InyeccionDependencias.ClaseDependiente2</value>
            </setting>
        </InyeccionDependencias.Properties.Settings>
    </applicationSettings>
</configuration>

Para entender como funciona esto, tan solo hay que ir cambiando el nombre de la clase que queramos inyectar en el archivo de configuración de la aplicación entre las tres clases disponibles (ClaseDependiente1, ClaseDependiente2 y ClaseDependiente3) y ver cómo se comporta el código paso a paso.

Tipos de inyección de dependencias

  1. Setter injection: El ejemplo que hemos visto se corresponde con este tipo, es decir, hemos dado a la clase principal su dependencia mendiante el set de una propiedad.
  2. Constructor injection: inyectar a la clase principal su dependencia en su constructor.
  3. Interface injection: La clase principal implementará otra interfaz que se definirá a través de la cual inyectaremos la dependencia.

A continuación os dejo el código fuente de lo que sería una constructor injection y de una interface injection:

Constructor injection:

using System;

namespace InyeccionDependencias
{
    class Program
    {
        static void Main(string[] args)
        {
            IClaseDependiente dependencia = ObtenerDependencia();

            // Inyectamos la dependencia en el constructor
            ClasePrincipal clasePrincipal = new ClasePrincipal(dependencia);

            clasePrincipal.HacerAlgo();

            Console.ReadLine();
        }

        /// <summary>
        /// Aqui es donde obtenemos la dependencia correspondiente
        /// a lo que ponga en el fichero de configuración de la aplicación.
        /// </summary>
        /// <returns></returns>
        static IClaseDependiente ObtenerDependencia()
        {
            string claseACrear = Properties.Settings.Default.NombreClase;
            Type tipo = System.Type.GetType(claseACrear);
            IClaseDependiente dependencia = (IClaseDependiente)Activator.CreateInstance(tipo);
            return dependencia;
        }
    }

    public interface IClaseDependiente
    {
        void HacerAlgo();
    }

    public class ClaseDependiente1 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 1");
        }
    }

    public class ClaseDependiente2 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 2");
        }
    }

    public class ClaseDependiente3 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 3");
        }
    }

    /// <summary>
    /// La clase principal no tiene conocimiento alguno acerca de las clases secundarias,
    /// solamente de su funcionalidad, a través de la interfaz.
    /// </summary>
    public class ClasePrincipal
    {
        IClaseDependiente claseDependiente;

        public ClasePrincipal(IClaseDependiente claseDependiente)
        {
            this.claseDependiente = claseDependiente;
        }

        public void HacerAlgo()
        {
            claseDependiente.HacerAlgo();
        }
    }
}

Interface injection:

using System;

namespace InyeccionDependencias
{
    class Program
    {
        static void Main(string[] args)
        {
            IClaseDependiente dependencia = ObtenerDependencia();

            // Inyectamos la dependencia en el constructor
            ClasePrincipal clasePrincipal = new ClasePrincipal();
            ((IInyectarDependencia)clasePrincipal).InyectarDependencia(dependencia);

            clasePrincipal.HacerAlgo();

            Console.ReadLine();
        }

        /// <summary>
        /// Aqui es donde obtenemos la dependencia correspondiente
        /// a lo que ponga en el fichero de configuración de la aplicación.
        /// </summary>
        /// <returns></returns>
        static IClaseDependiente ObtenerDependencia()
        {
            string claseACrear = Properties.Settings.Default.NombreClase;
            Type tipo = System.Type.GetType(claseACrear);
            IClaseDependiente dependencia = (IClaseDependiente)Activator.CreateInstance(tipo);
            return dependencia;
        }
    }

    public interface IClaseDependiente
    {
        void HacerAlgo();
    }

    public class ClaseDependiente1 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 1");
        }
    }

    public class ClaseDependiente2 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 2");
        }
    }

    public class ClaseDependiente3 : IClaseDependiente
    {
        public void HacerAlgo()
        {
            Console.WriteLine("Hacer algo desde la clase dependiente 3");
        }
    }

    /// <summary>
    /// La clase principal no tiene conocimiento alguno acerca de las clases secundarias,
    /// solamente de su funcionalidad, a través de la interfaz.
    /// </summary>
    public class ClasePrincipal : IInyectarDependencia
    {
        IClaseDependiente claseDependiente;

        public void HacerAlgo()
        {
            claseDependiente.HacerAlgo();
        }

        public void InyectarDependencia(IClaseDependiente claseDependiente)
        {
            this.claseDependiente = claseDependiente;
        }
    }

    public interface IInyectarDependencia
    {
        void InyectarDependencia(IClaseDependiente claseDependiente);
    }
}
Anuncios

Dejar un comentario »

Aún no hay comentarios.

RSS feed for comments on this post.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Crea un blog o un sitio web gratuitos con WordPress.com.

A %d blogueros les gusta esto: