Patrón Singleton con C#

Patxi Echarte, August 9th, 2005

Uno de los patrones de diseño sin lugar a dudas más utilizado y conocido, es el patrón Singleton. De forma resumida, un singleton en una clase que únicamente permite que exista simultaneamente una única instancia de si misma y que ofrece un punto de acceso común a ella.

Este patrón nos puede ayudar en situaciones en las que queramos que haya únicamente una única instancia de una clase, por ejemplo para tener un acceso centralizado a un sistema de log o un sistema de caché, de forma que desde cualquier punto de la aplicación en el que queramos utilizar estos recursos, podamos garantizar que accedamos siempre a la misma instancia.

El código necesario para poder disponer de un singleton es realmente sencillo, son básicamente 2 líneas, que podremos ampliar con el comportamiento específico que queramos darle.

// .NET Singleton
sealed class Singleton
{
    private Singleton() {}
    public static readonly Singleton Instance = new Singleton();
}

Para utilizar el código, podríamos usar desde cualquier punto Singleton.Instance y accederíamos siempre a la misma instancia.

Entrando un poco más al detalle del código utilizado, merece la pena explicar un par de cosas referentes a cómo se crea la instancia y cómo se evitan posibles problemas que podrían provocarse, sobretodo en entornos multihilo.

Lo primero de todo es destacar como el constructor de la clase está marcado como “private”, lo cual hace imposible crear instancias de la clase y nos obliga a acceder a la única posible instancia a través de la propiedad Instance. Con el mismo fin la clase está marcada como “sealed”, por lo que nos garantizamos de que nadie va a poder heredar de esta clase y crear múltiples instancias de nuestro singleton.

En cuanto a la instancia de la clase, está marcada como “public”, “readonly” y “static”, lo cual hace que se pueda acceder a ella desde cualquier otra parte, que no sea modificable y que se cree la primera vez que se acceda a ella, como veremos más adelante.

Hay un par de cuestiones típicas que suelen afectar a otras implementaciones de este patrón en otros lenguajes, una es la inicialización perezosa y la segunda los posibles problemas con el uso de múltiples hilos. La inicialización perezosa se refiere a la conveniencia por eficiencia, de no crear la instancia hasta el momento en que se acceda por primera vez a la instancia. En otros lenguajes esto se realiza mediante un “if” en un método “getInstance”, que comprueba si la instancia ha sido ya creada o no, de forma que se crea la primera vez que se llama al método. En situaciones multihilo esto puede provocar que varios hilos entre en el “if” a la vez, creando varias instancias. Para solventar este posible problema se suele utilizar una solución basada en un “Double-Check”, en la cual, lo primero que hace el método “getInstance” es comprobar si la instancia ha sido creada y en caso contrario entra en una “sección crítica”, en la cual se vuelve a realizar la comprobación y si sigue sin estar creada, se crea. De esta forma si dos hilos entran en el primer “if”, al llegar a la sección crítica sus accesos se serializarían, produciendo que el primero de ellos crease la instancia y al entrar el segundo, la comprobación de si existe la instancia fuera positiva. A continuación puede verse el código correspondiente a este funcinamiento en C#, aunque no es necesario utilizarlo, ya que el código mostrado anteriormente tiene la misma funcionalidad como veremos a continuación.

// Port to C#
class Singleton
{
    public static Singleton Instance() {
        if (_instance == null) {
            lock (typeof(Singleton)) {
                if (_instance == null) {
                    _instance = new Singleton();
                }
            }
        }
        return _instance;
    }
    protected Singleton() {}
    private static volatile Singleton _instance = null;
}

Como hemos visto anteriormente, en el primer código de implementación del patrón, el atributo Instance está marcado como “static”, con lo se consiguen los mismos resultados que con el código anterior, aprovechándonos de las características propias del Framework de .NET. En lo que respecta a la inicialización perezosa, el Framework de .NET crea las variables static la primera vez que se acceden a ellas, durante el proceso JIT (Just In Time compilation), de forma que si la variable no se usa, no se inicializa. Del mismo modo, en lo referente a la inicialización a salvo de problemas con múltiples hilos, el Framework garantiza que la inicialización de variables estáticas es “Thread safe”.

Referencias

Comparte esta información

Un comentario para “Patrón Singleton con C#”

  1. Singleton con y sin Singleton - .NET o no .NET, esa es la cuestión dice:

    […] Si alguien quiere una explicación más en detalle, se puede pasar por la MSDN o por aquí. […]

Deja un comentario