Gof – Singleton

Vamos a arrancar este 2012 retomando el tema de los patrones de diseño y en este primer post del año veremos el patrón de creación Singleton. La finalidad de Singleton es que solo se pueda crear una única instancia de una clase determinada. De esta forma nos aseguramos que nadie pueda crear instancias adicionales de la clase y que todos accedan a la misma instancia.

Veamos la definición de Wikipedia:

El patrón de diseño singleton (instancia única) está diseñado para restringir la creación de objetos pertenecientes a una clase o el valor de un tipo a un único objeto.

¿En qué casos nos puede resultar útil implementar Singleton? En clases que se encargan de controlar el acceso a un recurso único (imaginemos un archivo abierto en modo exclusivo) o cuando necesitamos tener disponible información que es única para el resto de los objetos.

Hecha la introducción, es hora de escribir código e implementar este patrón con C#. Para esto vamos a crear una nueva aplicación de Consola y agregar una clase llamada Singleton (sobre la cual aplicaremos el patrón).

El primer punto es hacer que la propia clase sea responsable de crear la única instancia de si misma. Para esto vamos a definir el constructor con el modificador private – para impedir que otros puedan crear instancias “desde afuera” – y marcar la clase como sealed – para evitar que se herede de la misma -.

Hagamos una pequeña pausa y veamos que nos dice MSDN de este último modificador:

El modificador sealed se puede aplicar a clases, métodos de instancia y propiedades. Una clase sealed no se puede heredar. Un método sellado reemplaza un método en una clase base, pero no se puede reemplazar también en una clase derivada. Cuando se aplica a un método o propiedad, el modificador sealed siempre se debe utilizar conoverride (Referencia de C#).

Bien, en este momento deberíamos tener la clase Singleton definida de la siguiente manera:

Singleton class

Singleton class

El proximo paso es permitir el acceso a la instancia mediante un método o propiedad de clase. Para esto vamos a agregar una propiedad de sólo lectura (la que llamaremos Instance) que sera responsable de crear y devolvernos la única instancia de la clase:

Instance property

Instance property

Como podemos ver, la primera vez que solicitamos una instancia de la clase, la propiedad Instance se encarga de crearla y asignarla a la propiedad privada instance. Finalmente se devuelve la instancia generada.

Para validar que solo existe un única instancia, vamos a escribir un simple test unitario en el cual crearemos dos objetos Singleton y los compararemos para confirmar si realmente son iguales:

Unit test

Unit test

Si ejecutamos el test, veremos que el mismo es correcto ya que ambos objetos apuntan a la misma y única instancia que se creó en memoria de la clase Singleton.

Test passed

Test passed

Pero esto tiene un pequeño problema, no soporta multi-thread. Al momento de validar si existe una instancia creada, lo hacemos preguntando si el valor de la propiedad instance es distinto de null. Si trabajamos en entornos multi-thread podría darse la situación en que múltiples hilos entren al mismo tiempo en dicho if, por lo que se podrían crear varias instancias de Singleton.

Esto podemos solucionarlo de una manera sencilla, generando un bloqueo (lock) dentro de Instance que nos permita sincronizar todos los accesos a la creación del objeto.

Ampliemos sobre lock consultando MSDN:

La instrucción lock permite garantizar que un subproceso no va a entrar en una sección crucial de código mientras otro subproceso ya se encuentre en ella. Si otro subproceso intenta entrar en un código bloqueado, esperará, o se bloqueará, hasta que el objeto se libere.

Lo que necesitamos para hacer esta validación, es crear un objeto del tipo Object que llamaremos sync y que utilizaremos en el bloqueo:

Sync property

Sync property

Si volvemos a correr el test, el mismo vuelve a pasar correctamente pero ahora con soporte multi-thread. 😉

Sin bien ya tenemos implementado el patrón Singleton en nuestra clase, veamos que hay una forma más simple de aplicarlo. Solo debemos definir la propiedad instance como readOnly. Este modificador nos va a permitir crear la instancia en la misma declaración de la propiedad evitando que se creen nuevas instancias luego.

Veamos de que se trata este modificador consultando una vez más MSDN:

La palabra clave readonly corresponde a un modificador que se puede utilizar en campos. Cuando una declaración de campo incluye un modificador readonly, las asignaciones a los campos que aparecen en la declaración sólo pueden tener lugar en la propia declaración o en un constructor de la misma clase.

Refactorizamos y obtendremos una nueva y más prolija clase Singleton 🙂

Refactorizando Singleton

Refactorizando Singleton

Cabe aclarar que el comportamiento es exactamente el mismo que el de la implementación del punto anterior.

Espero que les sea útil y tengan presente el patrón para, llegado el caso, decidan implementarlo.

Anuncios

Gof – Builder

En esta ocasión vamos a hablar sobre el patrón de creación Builder, y su hace referencia a su propósito, la construcción de objetos complejos.

El propósito de este patrón es el siguiente:

Simplificar la construcción de objetos complejos definiendo para ello una clase principal encargada de construir instancias de otras.

Otra definición valida es:

Separa la construcción de un objeto complejo de su representación para que el mismo proceso de construcción puede crear diferentes representaciones.

Debemos aplicar este patrón cuando:

  • El algoritmo para la construcción del objeto debe ser independiente de las partes que lo conforman.
  • Se requiere más de un constructor en una clase o el mismo comienza a tener muchas líneas de código.
  • Se requiere lógica en la construcción del objeto.
  • El proceso de construcción debe permitir diferentes representaciones del objeto que es construido.
  • La estructura interna de los objetos a construir es compleja.
  • Si los atributos internos son dependientes entre si.
  • Si utilizamos objetos que son difíciles, o poco convenientes, de obtener durante la creación.

Modelo del patrón Builder:

Modelo del patrón Builder

Modelo del patrón Builder

Lo primero que podemos notar es que tenemos un Director que será el encargado de la construcción de los objetos. También podemos observar que una de las clases más importantes aquí es Builder, la cual posee definiciones de los pasos que se deben seguir para poder construir un objeto – producto – en particular. Finalmente tenemos los constructores concretos del producto a retornar.

Para hacerlo más práctico, vayamos trabajando en un ejemplo. En este caso la idea es trabajar en un construcctor (o preparador) de cockteles 🙂 . Lo primero que vamos a representar es el constructor de cockteles, el cual vamos a llamar CocktailBuilder.

public abstract class CocktailBuilder
{
    protected Bebida bebida;

    public Bebida Bebida
    {
        get { return bebida; }
    }

    public abstract void BuildBebidaPrincipal();    
    public abstract void BuildBebidaSecundaria();
    public abstract void BuildHielos();
    public abstract void BuildAperitivo();
}

Podemos notar que posee métodos abstractos para la construcción de cada uno de los distintos componentes de la bebida. Estos serán implementados por los builders propios de cada bebida. Además podemos ver el Producto representado por el atributo del tipo Bebida, el cual va a estar definido de la siguiente manera:

public class Bebida
{
    private string _nombreBebida;
    private string _tipoBebida;
    private Dictionary<string, string> _contenido = new Dictionary<string, string>();

    public Bebida(string nombre, string tipo)
    {
        this._nombreBebida = nombre;
        this._tipoBebida = tipo;
    }

    public string this[string key]
    {
        get { return _contenido[key]; }
        set { _contenido[key] = value; }
    }

    public void Show()
    {
        Console.WriteLine("\n---------------------------");
        Console.WriteLine("{0}:", _nombreBebida.ToUpper());
        Console.WriteLine("Tipo de bebida: {0}", _tipoBebida);
        Console.WriteLine(" Bebida principal : {0}", _contenido["principal"]);
        Console.WriteLine(" Bebida secundaria : {0}", _contenido["secundario"]);
        Console.WriteLine(" Hielo: {0}", _contenido["hielo"]);
        Console.WriteLine(" Aperitivo : {0}", _contenido["aperitivo"]);
    }
}

Ahora vayamos a los builders concretos para cada tipo de bebida, en este vamos a crear uno para un gran clásico de Argentina el Fernet y otro para el trago Bloody Mary:

public class FernetBuilder : CocktailBuilder
{
    public FernetBuilder()
    {
        bebida = new Bebida("Fernet", "Digestivo");
    }

    public override void BuildBebidaPrincipal()
    {
        bebida["principal"] = "Fernet Branca";
    }

    public override void BuildBebidaSecundaria()
    {
        bebida["secundario"] = "Coca Cola";
    }

    public override void BuildHielos()
    {
        bebida["hielo"] = "2 cubitos";
    }
    public override void BuildAperitivo()
    {
        bebida["aperitivo"] = "Ninguno";
    }
}
public class BloodyMaryBuilder : CocktailBuilder
{
    public BloodyMaryBuilder()
    {
        bebida = new Bebida("Bloody Mary", "Refrescante");
    }

    public override void BuildBebidaPrincipal()
    {
        bebida["principal"] = "Vodka";
    }

    public override void BuildBebidaSecundaria()
    {
        bebida["secundario"] = "Zumo de Tomate";
    }

    public override void BuildHielos()
    {
        bebida["hielo"] = "1 cubito";
    }

    public override void BuildAperitivo()
    {
        bebida["aperitivo"] = "1 pizca de sal y pimienta negra";
    }
}

Bien, solo nos falta representar al Director, en nuestro caso lo vamos a denominar Barman:

public class Barman
{        
    public void Construct(CocktailBuilder cocktailBuilder)
    {
        cocktailBuilder.BuildBebidaPrincipal();
        cocktailBuilder.BuildBebidaSecundaria();
        cocktailBuilder.BuildHielos();
        cocktailBuilder.BuildAperitivo();
    }
}

Como podemos ver, este constructor tiene definido una serie “compleja” de pasos a seguir para conseguir nuestro refrescante trago!

Finalmente vamos a escribir el programa principal y a instanciar cada una de esta entidades:

class Program
{
    static void Main(string[] args)
    {
        CocktailBuilder builder;
        Barman barman = new Barman();

        builder = new FernetBuilder();
        barman.Construct(builder);
        builder.Bebida.Show();

        builder = new BloodyMaryBuilder();
        barman.Construct(builder);
        builder.Bebida.Show();

        Console.ReadLine();
    }
}

En la salida podemos observar que cada uno de los tragos fue preparado de formas diferentes:

Aplicando builder

Aplicando builder

Adjunto el modelo de clases utilizado en el ejemplo para que puedan compararlo con el modelo de este patrón:

Modelo del ejemplo

Modelo del ejemplo

+ Ventajas

  • Facilita el manejo y supervisación en la creación de objetos complejos,  y permite implementar caminos alternativos ante errores.
  • Facilita el control en la creación de objetos que recurren a recursos externos (por ejemplo a conexiones de base de datos).

– Desventajas:

  • Gran acoplamineto entre el Director, los Builders y el Producto, lo que implica un alto impacto ante cambios.

Patrones de diseño GoF

Los patrones de diseño son basicamente modelos que podemos utilizar para resolver exitosamente un problema. Otra definición valida es que son respuestas a problemas que se presentan una y otra vez en nuestras tareas cotidianas, soluciones probadas repetidamente.

En posts anteriores sobre OOD hablamos de los patrones SOLID y lo que ofrecían cada uno de ellos. En esta ocación vamos a ver los patrones de diseño GoF, sus siglas significan Gang of Four debido a sus creadores: Erich GammaRichard HelmRalph JohnsonJohn Vlisides.

Estos patrones de diseño tuvieron un gran éxito en el mundo de la informática a partir de la publicación del libro Design Patterns escrito a principios de los 90s y en el cual se recogen 23 patrones de diseño comunes.

Design Patterns

Design Patterns

Estos 23 patrones los vamos dividir en 3 grupos de acuerdo a la naturaleza de cada uno:

  • De creación: conciernen al proceso de creación de objetos.
  • Estructurales: tratan la composición de clases y objetos.
  • Comportamiento: caracterizan las formas en las que interactúan y reparten responsabilidades las distintas clases u objetos.

En posteriores post vamos a ir viendo uno por uno en detalle estos patrones, destacando las ventajas y desventajas de cada uno.