Menu
Coddy logo textTech

Padrão Singleton

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 65 de 87.

O Padrão Singleton é um padrão de projeto criacional que garante que uma classe tenha apenas uma instância em toda a sua aplicação, ao mesmo tempo que fornece um ponto de acesso global a essa instância. Isso é útil para recursos que devem ser compartilhados, como gerenciadores de configuração, pools de conexão ou serviços de log.

O padrão funciona tornando o construtor privado, impedindo a instanciação direta. Em vez disso, um método estático controla o acesso à instância única:

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // O construtor privado impede a instanciação direta
    private DatabaseConnection() {
        System.out.println("Connection created");
    }
    
    // Ponto de acesso global
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    
    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

Cada chamada para getInstance() retorna o mesmo objeto. A instância é criada apenas quando solicitada pela primeira vez—isso é chamado de inicialização preguiçosa:

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

System.out.println(db1 == db2);  // true - mesma instância

Os componentes principais de um Singleton são: um campo private static que contém a instância, um construtor private e um método public static que retorna a instância. Esta combinação garante que, não importa quantas vezes você solicite o objeto, você sempre obterá o mesmo.

challenge icon

Desafio

Fácil

Vamos construir um gerenciador de configuração para um aplicativo usando o Singleton Pattern! Seu gerenciador de configuração garantirá que todas as partes do seu aplicativo compartilhem as mesmas configurações, não importa quantas vezes elas solicitem acesso a ele.

Você organizará seu código em dois arquivos:

  • AppConfig.java: Crie uma classe Singleton que gerencia as configurações do aplicativo. Seu AppConfig deve ter:

    Um campo estático privado para manter a instância única.

    Um campo String privado chamado appName e um campo int privado chamado maxUsers.

    Um construtor privado que inicializa appName como "MyApplication" e maxUsers como 100, e então imprime AppConfig initialized.

    Um método estático público getInstance() que cria a instância apenas se ela ainda não existir (lazy initialization) e, em seguida, a retorna.

    Um método setAppName(String name) que atualiza o nome do aplicativo.

    Um método setMaxUsers(int max) que atualiza o número máximo de usuários.

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

  • Main.java: Demonstre que seu Singleton funciona corretamente! Você receberá duas entradas: um novo nome de aplicativo (String) e um novo valor de máximo de usuários (inteiro).

    Primeiro, obtenha uma instância de AppConfig e armazene-a em uma variável chamada config1. Chame displaySettings() para mostrar os valores padrão.

    Em seguida, atualize as configurações usando os valores de entrada chamando setAppName e setMaxUsers em config1.

    Obtenha outra instância e armazene-a em config2. Chame displaySettings() em config2 para provar que ela reflete as alterações feitas através de config1.

    Finalmente, imprima se ambas as referências apontam para o mesmo objeto: Same instance: [true/false] comparando config1 == config2.

Você receberá duas entradas em ordem: o novo nome do aplicativo (String) e o novo máximo de usuários (inteiro).

Este desafio demonstra o benefício central do Singleton Pattern: não importa quantas vezes você solicite a configuração, você sempre obtém a mesma instância com o mesmo estado compartilhado!

Folha de consulta

O Singleton Pattern garante que uma classe tenha apenas uma instância em toda a aplicação, fornecendo um ponto de acesso global a essa instância.

Componentes Chave:

  • Um campo private static que contém a instância única
  • Um construtor private para evitar a instanciação direta
  • Um método public static que retorna a instância

Implementação Básica:

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // Construtor privado evita a instanciação direta
    private DatabaseConnection() {
        System.out.println("Connection created");
    }
    
    // Ponto de acesso global
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    
    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

Uso:

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

System.out.println(db1 == db2);  // true - mesma instância

A instância é criada apenas quando solicitada pela primeira vez—isso é chamado de lazy initialization. Cada chamada para getInstance() retorna o mesmo objeto, garantindo um estado compartilhado em toda a aplicação.

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Ler entradas
        String newAppName = scanner.nextLine();
        int newMaxUsers = scanner.nextInt();
        
        // TODO: Obter a primeira instância de AppConfig e armazenar em config1
        
        // TODO: Chamar displaySettings() em config1 para mostrar os valores padrão
        
        // TODO: Atualizar as configurações usando setAppName e setMaxUsers em config1
        
        // TODO: Obter outra instância e armazenar em config2
        
        // TODO: Chamar displaySettings() em config2 para provar que as alterações são compartilhadas
        
        // TODO: Imprimir se ambas as referências apontam para o mesmo objeto:
        // "Same instance: [true/false]" usando config1 == config2
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos