Saltar al contenido

Patrón Singleton en Java, con ejemplos

El patrón de diseño "Singleton", que en ingeniería del software es un patrón diseñado para limitar la creación de objetos pertenecientes a una clase.

El proyecto de este post lo puedes descargar pulsando AQUI.

En este tutorial vamos a hablar del patrón de diseño "Singleton«, que en ingeniería del software es un patrón diseñado para limitar la creación de objetos pertenecientes a una clase. El objetivo de este patrón es el de garantizar que una clase solo tenga una instancia (o ejemplar) y proporcionar un punto de acceso global a ella. Este patrón; por ejemplo, suele ser utilizado para las conexiones a bases de datos.

Este patrón se implementa haciendo privado el constructor de la clase y creando (en la propia clase) un método que crea una instancia del objeto si este no existe. Veamos a continuación un ejemplo de este patrón en el que vamos a crear una clase llamada "SoyUnico" con un constructor que va a ser privado y un método llamado 'getSingletonInstance()' que será el encargado de crear una instancia de esta clase si no se ha creado todavía:

public class SoyUnico {

    private String nombre;
    private static SoyUnico soyUnico;

    // El constructor es privado, no permite que se genere un constructor por defecto.
    private SoyUnico(String nombre) {
        this.nombre = nombre;
        System.out.println("Mi nombre es: " + this.nombre);
    }

    public static SoyUnico getSingletonInstance(String nombre) {
        if (soyUnico == null){
            soyUnico = new SoyUnico(nombre);
        }
        else{
            System.out.println("No se puede crear el objeto "+ nombre + " porque ya existe un objeto de la clase SoyUnico");
        }
        
        return soyUnico;
    }
    
    // metodos getter y setter

}

Vemos como al llamar al método 'getSingletonInstance()'  pregunta si el atributo 'soyUnico‘ es null o no, y si no lo es lo crea. En el caso de que ya haya sido creado imprimirá un mensaje por pantalla diciéndonos que ya existe un objeto de esa clase.

Vamos a ver como efectivamente nos crea un solo objeto, ejecutando el siguiente código en el que llamamos dos veces el método 'getSingletonInstance()':

public class Main {

    public static void main(String[] args) {
        
        SoyUnico ricardo = SoyUnico.getSingletonInstance("Ricardo Moya");
        SoyUnico ramon = SoyUnico.getSingletonInstance("Ramón Invarato");
        
        // ricardo y ramon son referencias a un único objeto de la clase SoyUnico
        System.out.println(ramon.getNombre());
        System.out.println(ricardo.getNombre());   
    }
}

Como salida a este código tenemos lo siguiente:


Mi nombre es: Ricardo Moya
No se puede crear el objeto Ramón Invarato porque ya existe un objeto de la clase SoyUnico
Ricardo Moya
Ricardo Moya

Vemos como efectivamente cuando no hay un objeto de la clase "SoyUnico«, lo crea y si lo quiere volver a crear, el método nos dice que ya hay otro creado pero le asigna la referencia al objeto, es decir que las variables ‘ricardo’ y ‘ramon’ referencian al mismo y único objeto de la clase «SoyUnico"; tal y como podemos ver al preguntar por el atributo 'nombre' de la clase.

Por último este patrón no quedaría perfectamente implementado si no controlamos la copia (o clone) de los objetos de esta clase; por ello es importante sobrescribir el método ‘clone()', para que cuando se quiera clonar este objeto se lance una excepción. Este método lo sobrescribimos de la siguiente forma:

//Sobreescribimos el método clone, para que no se pueda clonar un objeto de esta clase
@Override
public SoyUnico clone(){
    try {
        throw new CloneNotSupportedException();
    } catch (CloneNotSupportedException ex) {
        System.out.println("No se puede clonar un objeto de la clase SoyUnico");
    }
    return null; 
}

Veamos que pasa si intentamos clonar el objeto de la clase "SoyUnico":

public class Main {

    public static void main(String[] args) {
        
        SoyUnico ricardo = SoyUnico.getSingletonInstance("Ricardo Moya");

        try{
            SoyUnico richard = ricardo.clone();
            System.out.println(richard.getNombre());
        }catch (NullPointerException ex){
            ex.printStackTrace();
        }
    }
}

Vemos que nos lanza una excepción y no nos permite clonar ese objeto.


Mi nombre es: Ricardo Moya
No se puede clonar un objeto de la clase SoyUnico
java.lang.NullPointerException
	at Main.Main.main(Main.java:21)

En resumen, en este tutorial se ha puesto un ejemplo muy sencillo para ver el funcionamiento del patrón "Singleton» que es un patrón de diseño muy utilizado (quizás el que más), aplicable en los casos en los que solo queremos tener un único objeto de la clase que implementamos.

«Patrón Singleton en Java, con ejemplos», de Ricardo Moya en jarroba.com, con licencia Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0. Obra registrada en Safe Creative.

Ricardo Moya

Me dedico profesionalmente al Machine Learning y al Big Data. Me gusta aprender tecnologías nuevas y explicarlas de la mejor manera posible en esta web.

Te puede interesar

Patrón Singleton en Python, con ejemplos

En este artículo vamos a describir el patrón singleton en Python que es un patrón que tiene como objetivo garantizar que una clase sólo tenga una instancia.

18 May 2017

Comentarios (21)

  1. Maximiliano

    Hola.

    El patron Singleton está desaconsejado.
    Puedes ver alguno de los argumentos aqui
    https://medium.com/@mcsee/singleton-el-patr%C3%B3n-del-mal-f3fdab0e16a2

    1. Ramón Invarato Jarroba.com

      Gracias Maximiliano.

      Correcto, es un patrón desaconsejado, que no prohibido. Siempre recomendamos utilizar otros patrones o soluciones alternativas al código para evitar utilizar Singleton por todos los argumentos que se mencionan.

      Sin embargo, en ocasiones no queda otra más que utilizarlo para compartir estados de memoria entre diferentes puntos del código en ciertas arquitecturas por la complicación de pasar estados complejos de una manera rápida y eficaz; por ejemplo, para pasar un objeto complejo en Android, compartir estados entre Activities o Fragments se hace complicado sin un patrón de este tipo (una solución alternativa es inicializar el objeto en cada clase, si el objeto realiza mucho cálculo supone una penalización muy grande tanto en tiempo de proceso como en batería del móvil para algo que ya se tenía calculado y que se puede pasar con un patrón Singleton).

      1. Dardo Dario CALLADO

        Me queda mi duda porque si hago:
        public static void main(String[] args) {
        SoyUnico ricardo = SoyUnico.getSingletonInstance(«Ricardo Moya»);
        SoyUnico ramon = SoyUnico.getSingletonInstance(«Ramon Miers»);
        SoyUnico dario = new SoyUnico(«dario»);

        System.out.println(ramon.getNombre());
        System.out.println(ricardo.getNombre());
        System.out.println(dario.getNombre());
        Si lo hago asi puedo instanciar un objeto sin necesidad de usar el metodo getSingleton osea que podria seguir instanciando….

        1. Ramón Invarato Jarroba.com en respuesta a Dardo Dario CALLADO

          Buenas Dardo.
          Para prevenir las instancias de una clase se puede hacer privado el constructor.
          De cualquier manera, la gracia de usar «getSingletonInstance» es obtener la instancia que previamente existe o crearla si no existe. Si se usa el constructor, siempre se crearía una nueva instancia.

  2. Gonzalo Mosquera

    Hola, gracias por la explicación, fue la más clara de tantos tutoriales que he visto, sigan así!!!

  3. alberto martín

    CUántos abremos aprendido java con vosotros!??!
    Gracias!!!

    1. Ramón Invarato Jarroba.com

      De nada Alberto. Nos alegra saber que los artículos ayudan 😉
      Un saludo.

  4. Lucas

    Excelente explicación. Muchas gracias

  5. Gabriel Carrillo

    Muchas gracias me ayudo mucho y esta muy bien explicado

  6. Aleks

    Muuuuchisimas gracias me has salvado

  7. Miguel

    Muy clara la explicación y útil, mil gracias.

    1. Ella

      salame

  8. Roberto Barrientos

    si mando a llamar el método getSingletonInstance, para después mandar los setters con los valores esto no tendría ningún problema, cierto?

    1. Ramón Invarato Jarroba.com

      No deberías tener ningún problema, pues con getSingletonInstance te devuelve el puntero al objeto entero. te podría dar problemas si devuelve Null, que no debiera.

  9. ¡Explicación simple! Me ha sido útil. Muchas gracias.

  10. glend

    Es aconsejable utilizar el patrón singleton para un sistema web?

    creo que podría generar bloqueos si solo se usa una conexión.

    1. Ramón Invarato Jarroba.com

      El patrón Singleton es muy útil en ciertos casos, pero sí que pudiera haber problemas con la multitaréa (si utilizas por ejemplo Spring), siempre puedes poner syncronized para evitar problemas pero esperas vas a tener. Dependerá de lo que necesites.

  11. fas

    Asi como el clone no faltaria algo para el tema de multiples hilos accediendo?

  12. Raúl

    Gracias por la explicacion!

  13. Agustín

    Hola! Y feliz Navidad!

    Entonces, en realidad si podríamos clonarlo pero estaría conceptualmente mal, no??

     

    Saludos

    Agustín

    1. Ricardo Moya Jarroba.com

      Hola Agustín.

      La idea del patron singleton es que solo haya un objeto de esa clase. Si lo clonamos obviamente habrá 2 o más objetos con lo cual no tendría sentido utilizar este patrón. No es que conceptualmente este mal, pero haciendo un clone no estarías utilizando este patrón. Normalmente cuando he utilizado este patrón no he implementado la excepción del clone ya que asumo que estoy utilizando ese patrón y no voy a clonar ese objeto, pero lo pongo en este tutorial por si acaso.

      Saludos

Deja un comentario


Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.