Menu
Coddy logo textTech

Patrón Singleton

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy. Lección 65 de 87.

El patrón Singleton es un patrón de diseño creacional que garantiza que una clase tenga una sola instancia en toda tu aplicación, al tiempo que proporciona un punto de acceso global a esa instancia. Esto resulta útil para recursos que deben compartirse, como gestores de configuración, grupos de conexiones o servicios de registro.

El patrón funciona haciendo privado el constructor, lo que impide la instanciación directa. En su lugar, un método estático controla el acceso a la única instancia:

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // El constructor privado previene la instanciación directa
    private DatabaseConnection() {
        System.out.println("Connection created");
    }
    
    // Punto de acceso global
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    
    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

Cada llamada a getInstance() devuelve el mismo objeto. La instancia se crea únicamente cuando se solicita por primera vez. Esto se denomina inicialización diferida:

DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();

System.out.println(db1 == db2);  // true - same instance

Los componentes clave de un Singleton son: un campo private static que contiene la instancia, un constructor private y un método public static que devuelve la instancia. Esta combinación garantiza que, sin importar cuántas veces solicites el objeto, siempre obtengas el mismo.

challenge icon

Desafío

Fácil

¡Construyamos un gestor de configuración para una aplicación usando el patrón Singleton! Tu gestor de configuración garantizará que todas las partes de tu aplicación compartan la misma configuración, sin importar cuántas veces soliciten acceder a ella.

Organizarás tu código en dos archivos:

  • AppConfig.java: Crea una clase Singleton que administre la configuración de la aplicación. Tu AppConfig debe tener:

    Un campo estático privado para almacenar la única instancia.

    Un campo privado de tipo String llamado appName y un campo privado de tipo int llamado maxUsers.

    Un constructor privado que inicialice appName con "MyApplication" y maxUsers con 100, después imprima AppConfig initialized.

    Un método estático público getInstance() que cree la instancia solo si todavía no existe (inicialización diferida) y después la devuelva.

    Un método setAppName(String name) que actualice el nombre de la aplicación.

    Un método setMaxUsers(int max) que actualice el número máximo de usuarios.

    Un método displaySettings() que imprima App: [appName], Max Users: [maxUsers].

  • Main.java: ¡Demuestra que tu Singleton funciona correctamente! Recibirás dos entradas: un nuevo nombre de aplicación (String) y un nuevo valor máximo de usuarios (entero).

    Primero, obtén una instancia de AppConfig y almacénala en una variable llamada config1. Llama a displaySettings() para mostrar los valores predeterminados.

    Después, actualiza la configuración usando los valores de entrada mediante una llamada a setAppName y setMaxUsers en config1.

    Obtén otra instancia y almacénala en config2. Llama a displaySettings() en config2 para demostrar que refleja los cambios realizados mediante config1.

    Finalmente, imprime si ambas referencias apuntan al mismo objeto: Same instance: [true/false], comparando config1 == config2.

Recibirás dos entradas en orden: el nuevo nombre de la aplicación (String) y el nuevo número máximo de usuarios (entero).

Este desafío demuestra el beneficio principal del patrón Singleton: ¡sin importar cuántas veces solicites la configuración, siempre obtendrás la misma instancia con el mismo estado compartido!

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Leer entradas
        String newAppName = scanner.nextLine();
        int newMaxUsers = scanner.nextInt();
        
        // TODO: Obtén la primera instancia de AppConfig y guárdala en config1
        
        // TODO: Llama a displaySettings() en config1 para mostrar los valores predeterminados
        
        // TODO: Actualiza la configuración usando setAppName y setMaxUsers en config1
        
        // TODO: Obtén otra instancia y guárdala en config2
        
        // TODO: Llama a displaySettings() en config2 para demostrar que los cambios se comparten
        
        // TODO: Imprime si ambas referencias apuntan al mismo objeto:
        // "Same instance: [true/false]" using config1 == config2
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Java online