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 Singleton Pattern é um padrão de projeto criacional que garante que uma classe tenha apenas uma instância em toda a sua aplicação, além de fornecer 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 registro.

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

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // 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 a getInstance() retorna o mesmo objeto. A instância é criada somente quando solicitada pela primeira vez. Isso é chamado de inicialização tardia:

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

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

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

challenge icon

Desafio

Fácil

Vamos criar um gerenciador de configuração para uma aplicação usando o Padrão Singleton! Seu gerenciador de configuração garantirá que todas as partes da sua aplicação compartilhem as mesmas configurações, não importa quantas vezes solicitem acesso a elas.

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

  • AppConfig.java: crie uma classe Singleton que gerencie as configurações da aplicação. Seu AppConfig deve ter:

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

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

    Um construtor privado que inicialize appName com "MyApplication" e maxUsers com 100, e depois imprima AppConfig initialized.

    Um método estático público getInstance() que crie a instância somente se ela ainda não existir (inicialização tardia) e depois a retorne.

    Um método setAppName(String name) que atualize o nome da aplicação.

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

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

  • Main.java: demonstre que seu Singleton funciona corretamente! Você receberá duas entradas: um novo nome de aplicação (String) e um novo valor 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 exibir 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 por meio de config1.

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

Você receberá duas entradas, nesta ordem: o novo nome da aplicação (String) e o novo número máximo de usuários (inteiro).

Este desafio demonstra o principal benefício do Padrão Singleton: não importa quantas vezes você solicite a configuração, sempre obterá a mesma instância com o mesmo estado compartilhado!

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: Obtenha a primeira instância de AppConfig e armazene em config1
        
        // TODO: Chame displaySettings() em config1 para mostrar os valores padrão
        
        // TODO: Atualize as configurações usando setAppName e setMaxUsers em config1
        
        // TODO: Obtenha outra instância e armazene em config2
        
        // TODO: Chame displaySettings() em config2 para provar que as alterações são compartilhadas
        
        // TODO: Imprima se ambas as referências apontam para o mesmo objeto:
        // "Same instance: [true/false]" using 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

Pratique por conta própria: Compilador de Java online