Cidenet+Blog+Desarrollo limpio+Singleton

Singleton

¿Qué es?, ¿Qué problema resuelve?

El patrón Singleton se utiliza para asegurar que una clase tiene máximo una instancia y provee un punto global de acceso a esta instancia, si en el código existen creaciones de objetos.

Este patrón resuelve dos problemas:

  1. Asegurar que una clase tiene una única instancia: Esto puede ser útil ante la necesidad de controlar el acceso a un recurso compartido, por ejemplo, un archivo o un componente de una interfaz.
  2. Proveer un punto de acceso global a esa instancia: El patrón Singleton permite acceder a un objeto desde cualquier lugar del programa. Sin embargo, también protege esa instancia de ser actualizada por otro código.

Diagrama


Singleton: Define un método que permite a los clientes acceder a su única instancia. También es responsable de crear su única instancia.

El código cliente accede a la instancia del Singleton únicamente a través del método que otorga el mismo Singleton.

El patrón Singleton se puede utilizar en el patrón Factory para tener un único objeto por cada ConcreteCreator, en este ejemplo se tomará el ejemplo utilizado para ilustrar la estructura del patrón Factory y se convertirá un ConcreteCreator en un Singleton. Esto se hace porque en realidad los objetos de cada ConcreteCreator, al crearse, siempre van a ser iguales y no es óptimo tener varias instancias que son iguales.

Para este ejemplo tomaremos la clase JSONConverter; para volver esta clase un Singleton, se debe:
Crear dentro de la clase JSONConverter una instancia privada de la misma clase.

private static JSONConverter jsonConverter;

Hacer el constructor de clase privado:

private JSONConverter(){}

Crear el método getInstance, el cual es el punto de acceso de la instancia privada, este método inicializa el objeto privado si no se había llamado antes. En caso de haberse llamado antes, símplemente se retorna la instancia antes creada.

private JSONConverter(){}
public static JSONConverter getInstance() {
    if(jsonConverter == null) {
        jsonConverter = new JSONConverter();
    }
    return jsonConverter;
}

En el método del Director, el cual selecciona qué ConcreteCreator, debe retornar se debe cambiar el new por la llamada al método expuesto por JSONConverter.

public static Converter getConverter(ConverterType format) {
    switch (format) {
        case JSON:
        return JSONConverter.getInstance();
    }
}

Para probar que los objetos del JSONConverter son idénticos se hacen dos pruebas unitarias (imagen 6), una donde se comparan dos ConcreteCreator del tipo JSON y otra prueba donde se comparan dos ConcreteCreator del tipo XML. Notamos como para JSON los objetos efectivamente apuntan a un único objeto y como para XML se tienen dos instancias diferentes. Con este patrón nos ahorramos espacio de memoria evitando crear múltiples objetos que están concebidos para ser iguales.

Cabe resaltar cómo gracias a que se aplicó el patrón Factory, se pudo hacer un cambio a un ConcreteCreator y su uso en las pruebas unitarias no se vió afectado, ya que gracias al Creator siempre se tiene la certeza que este va a retornar un Converter sin importar este como lo ha obtenido.

@Test
public void shouldGetSameConcreteCreatorInstance() {
    assertEquals(Director.getConverter(ConverterType.JSON), 
                 Director.getConverter(ConverterType.JSON));
}

@Test
public void shouldGetDifferentConcreteCreatorInstance() {
    assertNotEquals(Director.getConverter(ConverterType.XML), 
                 Director.getConverter(ConverterType.XML));
}

Conclusiones

  • Como la clase Singleton encapsula su instancia, se puede tener un control estricto sobre cómo un cliente accede a esta instancia.
  • El objeto Singleton se inicializa sólo cuando es requerido la primera vez, si no se ha requerido nunca, no se inicializa.
  • Abstract Factory, Factory Method, Builder y Prototype pueden implementarse como Singleton.

El ejemplo del código se puede encontrar en https://bit.ly/3k60MsS

Fuentes

Contáctanos

Déjanos tus datos

    Medellín - Colombia

  • Calle 47D #72-29
  • (+57) 4 3222567
  • comunicaciones@cidenet.com.co

    Estados Unidos

  • 1200 Colorado Blvd, Denver Colorado 80220
  • (+1) 7723619239
  • jceballos@cidenet.net
WhatsApp