Archive for the ‘Patterns’ Category

Inyección de Dependencia con Spring.Net

Spring.Net es uno de los frameworks más conocidos para implementar Inyección de Dependencia (también conocido como Inversión de Control -IoC). Otros que nos permiten hacer este trabajo son: PicoContainer, ObjectBuilder, Windsor Container.

Basicamente, qué queremos lograr? Fácil, crear nuestros objetos, sin importar quién me provea la implementación.

En vez de hacer esto:

(1) Cliente obj_cliente = new Cliente();

Podemos hacer esto:

(2) ICliente obj_cliente = (ICliente) AppContext.Instance.GetObject("Cliente");

Expliquemos, en (1) le estamos diciendo a obj_cliente quién va a crearlo: new Cliente(); Es decir, le estamos diciendo quien le va a proveer de la implementación, y nunca vamos a poder cambiar esto, a menos que lo hagamos y volvamos a compilar. En (2) es distinto, estamos pidiendo una implementación, pero no sabemos quien nos la va a dar. Solo sabemos que quién nos proveea la construcción, va a implementar la interfaz ICliente. AppContext es un wrapper que hice para crear un singleton del contexto de toda la aplicación (está en el codigo fuente que se puede descargar más abajo).

El lugar donde le decimos qué clase se va a encargar de la implementación, es en el app.config (en una de las tantas lineas para configurar Spring.Net):

<object name=”Cliente” type=”Entities.Cliente, Entities” singleton=”false”/>

En esta línea de código Entities.Cliente es la Clase que nos proveerá la implementación, y Entities es el assembly (que TIENE que estar en la carpeta de salida, donde está el .exe). También podemos ver cuan fácil es implementar un singleton de esta manera, solamente escribiendo singleton=”true” (ú obviandolo, es el valor por defecto), entonces no tenemos que hacerlo programaticamente.

Para el ejemplo lo que hice es organizar los proyectos de esta forma:

Lo que hariamos normalmente es referenciar Entities desde todas las partes del proyecto, en vez de esto, lo haremos con Entities.Contracts que contienen las interfaces, de modo que siempre programaremos contra las interfaces, nunca contra la implementación. Los proyectos no poseen relación de conocimiento con Entities, en ningún momento se lo referencia.

El tip del día: Hay que programar contra las interfaces.

Descargar codigo fuente [Proyecto hecho con SharpDevelop]

Donde más podemos utilizarlo ? En la capa de acceso a datos, podríamos persistir los objetos con db4o, y en otra implementación lo podríamos hacer usando NHibernate! Y esto lo lograríamos creando una interfaz IBaseRepository que tenga metodos como Guardar, Eliminar, Buscar y luego crear las implementaciones para cada uno de los providers por ejemplo BaseRepositoryDb4o y BaseRepositoryNH.

Espero que sirva!

Predicados y especificaciones

Inspirado en este post, decidí hacerme un ejemplito de predicados en .Net y así utilizar el patrón especificaciones.

Un predicado es un delegado que apunta a funciones que devuelven un valor booleano y aceptan un objeto genérico.

Vamos a ver una forma interesante de hacer filtrados en base a ciertos criterios de selección utilizando estos dichosos predicados de .Net.

Ciertamente podríamos implementar esto de la forma que siempre se hace, realizar un filtrado, iterando en una colección, y preguntando si tal elemento, se corresponde con el criterio elegido. Por ejemplo: recorrer la lista y vamos preguntando: este cliente…tiene correo gmail ?

Podría esbozarse un código como este:

 static public IList<Cliente> HasGmail(IList<Cliente> lista)
        {
            IList<Cliente> lista_resultado = new List<Cliente>();

            foreach(Cliente c in lista)
            {
                if(c.Email.Contains("@gmail.com"))
                {
                    lista_resultado.Add(c);
                }
            }
            return lista_resultado;
        }

Y se llamaría así:

IList<Cliente> usuariosDeGmail = ClienteFinder.HasGmail(lista);

Pero ahora bien, se podría objetizar el código, y hacerlo un poco más flexible, y hacer uso de predicados.

Podríamos reemplazarlos por esto:

IList<Cliente> usuariosDeGmail = 
                new ClienteFinder(lista).Find(EmailSpec.HasGmail);

Parecería estar más complicado, pero el concepto es sencillo y aplica el patrón de especificaciones, mediante predicatos genéricos.

Vamos al codigo de la entidad de negocio de la cual tenemos un listado y la queremos obtener por un criterio: la entidad Cliente.

public class Cliente
    {
        public Cliente()
        { }

        public Cliente(string nombre, string email)
        {
            this.nombre = nombre;
            this.email = email;
        }
        private string nombre;

        public string Nombre
        {
            get { return nombre; }
            set { nombre = value; }
        }

        private string email;

        public string Email
        {
            get { return email; }
            set { email = value; }
        }
    }

El código principal sería así:

 static void Main(string[] args)
        {
            CargarLista();

            //IList<Cliente> usuariosDeHotmail = new ClienteFinder(lista).Find(EmailSpec.HasHotmail);
            IList<Cliente> usuariosDeGmail = new ClienteFinder(lista).Find(EmailSpec.HasGmail);

            foreach (Cliente cliente in usuariosDeGmail)
            {
                Console.WriteLine("Email: {0}", cliente.Email);
            }

            Console.Read();
        }

Veamos el código de las especificaciones que se puede aplicar para obtener distintos criterios de filtrado:

public class EmailSpec
{
    public static Predicate<Cliente> HasHotmail
    {
        get{
            return delegate(Cliente cliente)
            {
                return cliente.Email.Contains("@hotmail.com");
            };

        }
    }

    public static Predicate<Cliente> HasGmail
    {
        get
        {
            return EmailSpec.MethodHasGmail;
        }
    }

    public static bool MethodHasGmail(Cliente cliente)
    {
        return cliente.Email.Contains("@gmail.com");
    }

    public static Predicate<Cliente> HasYahoo
    {
        get
        {
            return new Predicate<Cliente>(EmailSpec.MethodHasYahoo);
        }
    }

    public static bool MethodHasYahoo(Cliente cliente)
    {
        return cliente.Email.Contains("@yahoo.com");
    }

}

Aquí podemos ver, primeramente el uso de retorno de delegados usando Métodos anónimos (en HasHotmail), delegados con inferencia de tipos (en HasGmail) y la forma natural de usar un delegado (en HasYahoo). Estas son tres formas de hacer lo mismo, y yo recomiendo usar métodos anónimos que se vé en la propiedad HasHotmail y en este caso, el código se vuelve mucho más chico.

 public static Predicate<Cliente> HasHotmail
    {
        get{
            return delegate(Cliente cliente)
            {
                return cliente.Email.Contains("@hotmail.com");
            };

        }
    }

Vemos que la propiedad es de sólo lectura, y que también, retorna un predicado, que hablando mal, devolvería la función que se encargaría de la evaluación…y esa función…devolvería un booleano…true OR false, si cumple ó no. Muy prolijo no ? Sería lo mismo hacer:

  public static Predicate<Cliente> HasHotmail
    {
        get{
            return delegate(Cliente cliente)
            {
                if(cliente.Email.Contains("@hotmail.com"))
                    return true;
                else
                    return false;
            };

        }
    }

Ahora veamos el código de ClienteFinder:

public class ClienteFinder
{
    private IList<Cliente> _lista;

    public ClienteFinder(IList<Cliente> lista)
    {
        _lista = lista;
    }

    public IList<Cliente> Find(Predicate<Cliente> predicate)
    {
        List<Cliente> encontrados = new List<Cliente>();

        foreach (Cliente cliente in _lista)
        {
            if (predicate(cliente))
            {
                encontrados.Add(cliente);
            }
        }

        return encontrados;
    }

}

Lo importante acá es el constructor, que va a recibir la lista a ser filtrada. Y también el método Find, quien va a recibir el predicado correspondiente al criterio de selección. Es decir que Find puede recibir cualquiera de las tres especificaciones que preparamos: HasHotmail, HasGmail, HasYahoo, y realizar el filtrado en base a ellas.

Recursos:

Patron Proxy en C#

Este es un ejemplo del Patron Proxy adaptado x mí, lo traté de hacer lo suficientemente claro para que no requiera mucha explicación, pero…basicamente es:Empleado deriva de IPersona.
Defino los metodos de Empleado (que son los metodos reales)
Despues defino el Proxy que tambien deriva de IPersona, de modo que aun no estando instanciado realmente en memoria, puedo ocupar los metodos, de manera que retraso la instanciación (que es una de las motivaciones de este patron).
Cuando deseo ocupar los metodos de Empleado, no lo trato directamente con él, sino con su delegado, es decir, el Proxy.


//
// Ejemplo Utilizando el patron Proxy
//
using System;

namespace sampleProxy3
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
  IPersona obj = new Proxy();

  obj.PonerNombre("dario"); //este es el momento en que se crea
                             verdaderamente el objeto pero ya puedo
                             ocupar sus metodos.
  obj.Imprimir();
  Console.ReadLine();
}
}

public interface IPersona
{
string ObtenerNombre ();
void PonerNombre (string nombre);
void Imprimir();
}

public class Empleado : IPersona
{
string Nombre;
public Empleado(string nombre)
{
  this.Nombre = nombre;
}
public Empleado(){}
#region Miembros de IPersona

public string ObtenerNombre()
{
  return this.Nombre;
}

public void PonerNombre(string nombre)
{
  this.Nombre = nombre;
}
public void Imprimir()
{
  Console.WriteLine("El nombre es: "+this.Nombre);
}
#endregion
}

public class Proxy : IPersona
{
Empleado emp;
public void PonerNombre(string nombre)
{
  if (emp == null)
  {
      emp = new Empleado();
  }
  emp.PonerNombre(nombre);
}

public void Imprimir()
{
  if (emp == null)
  {
      emp = new Empleado();
  }
  emp.Imprimir();
}

public string ObtenerNombre()
{
  if (emp == null)
  {
      emp = new Empleado();

  }
  return emp.ObtenerNombre();
}

}
}

Un ejemplo de esto más tangible, es lo que hace el Visual Studio cuando se Agrega una Referencia Web -un Web Service-. Como vamos a necesitar ocupar los metodos del Web Service que lo tenemos en otra parte del mundo, primero te genera un proxy para que vos puedas interactuar con los metodos de las clases originales, sin interactuar con el objeto instanciado. De modo que el Intellisense nos deja ver todo lo que tiene para ofrecernos el Web Service.