Effective Java: C#, 3: Refuerza la propiedad singleton con un constructor privado o un tipo enumerado

13mar10

No traduzco el término singleton, que significa conjunto con un solo elemento y que se usa para referirse a una clase de la que sólo hay una instancia. El singleton es uno de los patrones de diseño más utilizados. Si estamos haciendo logging, por ejemplo, es probable que sólo queramos una instancia del logger a la que podamos acceder desde cualquier punto del programa. Elsingleton es una solución comúnmente adoptada para no crear más de una instancia del objeto y hacerlo accesible.

Bloch propone en su libro el abandono de una práctica Java en favor de otra que sólo se ha hecho posible desde la aparición de Java 1.5.  El nuevo método pasa por usar tipos enumerados. Este es un campo en el que Java ofrece un modelo sustancialmente diferente del de C#. En C# los tipos enumerados son conjuntos de constantes de algún tipo entero (excepto char). En Java, el tipo enumerado define una clase nueva de la que las constantes son instancias de sólo lectura. Esa nueva clase puede contener campos y métodos, como cualquier otra clase. Implementar el singleton resulta sencillo: se define un tipo enumerado con un único valor, que será la instancia única. Bloch comenta que esa aproximación ofrece ventajas, como la adición gratuita de maquinaria de serialización y resistencia a ataques por reflexión. Pero hay algo que no me gusta si se sigue la propuesta al pie de la letra: la clase debe implementarse pensando en que sólo será usada como singleton. Se puede dar un rodeo y montar como tipo enumerado una clase con un campo de sólo lectura que sea, precisamente, de la clase que ofrece el verdadero servicio y que se diseñó sin seguir el patrón en cuestión. Pero la sintaxis se complicará al acceder a la instancia que nos interesa, ya que ahora será un campo de la instancia de tipo enumerado que ofrece el punto de entrada. Y un último problema, que a mi juicio no es menor: no tenemos control del proceso de instanciación. La instancia se inicializará cuando Java lo considere oportuno, y sospecho (no estoy seguro) de que esto ocurrirá al inicio del programa. Si el objeto único tiene un proceso de construcción pesado, puede que no deseemos que se construya hasta que se use efectivamente. De ese modo aligeramos el tiempo de arranque del programa y, si nadie hiciese un acceso al singleton, evitaríamos completamente su construcción.

C# 4.0 ofrece un nuevo tipo de datos genérico que parece apropiado para implementar los singleton: Lazy<T>. Si deseamos una instancia de tipo T, Lazy<T> se asegura de que sólo se instancie cuando se accede a ella por primera vez.


public class SingletonClass
{
    static Lazy<SingletonClass> Instance = new Lazy<SingletonClass>();

    public readonly int n = 1;
}

public class Clase
{
    public static void Main(string[] args)
    {
        System.Console.WriteLine(SingletonClass.Instance.Value.n);
        System.Console.Read();
    }
}

Si no gusta tener que acceder a través de Value, se puede dar un rodeo:


public class SingletonClass
{
    static Lazy<SingletonClass> instance = new Lazy<SingletoClass>();
    public static SingletonClass Instance { get { return instance.Value; } }

    public readonly int n = 1;
}

public class Clase
{
    public static void Main(string[] args)
    {
        System.Console.WriteLine(SingletonClass.Instance.n);
        System.Console.Read();
    }
}

No parece un gran avance: podíamos hacer algo parecido fijandoel tipo de instance a T e inicializándolo a null. La propiedad Instance, antes de devolver el valor de instance, miraría si instance es null y, de ser el caso, inicializaría instance.  Pero hay una ventaja adicional en el uso de Lazy<T>: si nuestro programa tiene hebras, Lazy<T> se asegura de que la instancia no se cree dos veces. Controlar esto a mano es pesado. Finalmente, con ciertas sobrecargas del constructor podemos controlar con qué método (una función anónima, por ejemplo) se construye la instancia, lo que permite, por ejemplo, recurrir a factorías en la inicialización del singleton o pasar al constructor parámetros.



Una respuesta a “Effective Java: C#, 3: Refuerza la propiedad singleton con un constructor privado o un tipo enumerado”

  1. 1 Ricardo

    Tiene muy buena pinta el nuevo tipo Lazy!!

    Hasta ahora en C# había que montar cosas muy raras para lograr un singleton con garantias de que fuese thread-safe:

    http://www.yoda.arachsys.com/csharp/singleton.html

    Salut,
    Ricardo


Deja un comentario

Fill in your details below or click an icon to log in:

Logo de WordPress.com

You are commenting using your WordPress.com account. Log Out / Cambiar )

Twitter picture

You are commenting using your Twitter account. Log Out / Cambiar )

Facebook photo

You are commenting using your Facebook account. Log Out / Cambiar )

Connecting to %s


Seguir

Get every new post delivered to your Inbox.