Padrão de design Singleton: Implementação e Exemplos de Uso

Entendendo o Padrão Singleton

O que é o Padrão Singleton?

O padrão Singleton é um padrão de projeto que garante a existência de apenas uma instância de uma determinada classe durante a execução do programa. Ele fornece um ponto de acesso global a essa instância, facilitando o seu uso.

Quando usar o Padrão Singleton?

O Singleton é útil quando precisamos de uma única instância de uma classe para controlar ações. É comum em casos onde se precisa coordenar ações em um sistema ou quando objetos mais pesados, como conexões de banco de dados, precisam ser gerenciados.

Implementação do Padrão Singleton

Implementação Básica

A implementação básica do padrão Singleton envolve a criação de uma classe com um método que cria uma nova instância da classe se uma ainda não existir. Se uma instância já existir, ele simplesmente a retorna.

C#
using System;

public class Singleton
{
    private static Singleton instance;
    
    // Construtor privado para evitar instanciação direta
    private Singleton()
    {
        Console.WriteLine("Instância criada.");
    }
    
    // Método estático para obter a instância única
    public static Singleton GetInstance()
    {
        if (instance == null)
        {
            instance = new Singleton();
        }
        
        return instance;
    }
    
    public void SomeMethod()
    {
        Console.WriteLine("Executando método da instância Singleton.");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        // Obter a instância do Singleton
        Singleton singleton1 = Singleton.GetInstance();
        singleton1.SomeMethod(); // Executar método na instância
        
        // Obter a mesma instância novamente
        Singleton singleton2 = Singleton.GetInstance();
        singleton2.SomeMethod(); // Executar método na instância novamente
        
        // Verificar se as instâncias são iguais
        Console.WriteLine(singleton1 == singleton2); // Retorna true, pois é a mesma instância
        
        // Tentar criar uma nova instância diretamente
        // Singleton singleton3 = new Singleton(); // Isso não é permitido, pois o construtor é privado
    }
}

// Fonte: ChatGPT

Neste exemplo, a classe Singleton implementa o padrão Singleton. Ela possui um construtor privado para evitar a criação direta de instâncias e um método estático GetInstance() que retorna a instância única. Quando o método GetInstance() é chamado pela primeira vez, uma nova instância é criada. Nas chamadas subsequentes, a mesma instância é retornada.

No método Main, demonstramos o uso do padrão Singleton ao obter a instância do Singleton e executar um método na mesma. Em seguida, obtemos a instância novamente e verificamos se é a mesma instância, o que retorna true. Além disso, mostramos que a tentativa de criar uma nova instância diretamente é impedida pelo construtor privado.

Implementação com thread-safe

Em ambientes multithread, a implementação básica pode levar a problemas. Nesses casos, podemos adicionar um bloqueio de thread (sincronização) para garantir que apenas um thread possa criar uma instância.

C#
using System;

public class Singleton
{
    private static Singleton instance;
    private static readonly object lockObject = new object();

    // Construtor privado para evitar instanciação direta
    private Singleton()
    {
    }

    // Método público estático que retorna a única instância da classe
    public static Singleton GetInstance()
    {
        // Verifica se a instância já foi criada
        if (instance == null)
        {
            // Bloqueia o acesso simultâneo de múltiplas threads
            lock (lockObject)
            {
                // Verifica novamente se a instância ainda é nula (pode ter sido criada por outra thread)
                if (instance == null)
                {
                    // Cria uma nova instância da classe
                    instance = new Singleton();
                }
            }
        }

        // Retorna a instância existente ou a recém-criada
        return instance;
    }

    public void PrintMessage(string message)
    {
        Console.WriteLine(message);
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        // Obtem a instância do Singleton
        Singleton singleton1 = Singleton.GetInstance();

        // Chama o método da instância
        singleton1.PrintMessage("Olá, eu sou a instância 1!");

        // Obtem outra instância do Singleton
        Singleton singleton2 = Singleton.GetInstance();

        // Chama o método da instância
        singleton2.PrintMessage("Olá, eu sou a instância 2!");

        // Verifica se as duas instâncias são iguais
        Console.WriteLine("As duas instâncias são iguais? " + (singleton1 == singleton2));

        // Aguarda a pressão de uma tecla para encerrar o programa
        Console.ReadKey();
    }
}

// Fonte: ChatGPT

Neste exemplo, a classe Singleton implementa o padrão Singleton. O método GetInstance() retorna a única instância da classe, garantindo que apenas uma instância seja criada mesmo em ambientes multithread. A classe Program demonstra o uso do Singleton, onde são obtidas duas instâncias do Singleton e verificado se são iguais.

Implementação com Lazy Initialization

Em algumas situações, queremos adiar a criação da instância Singleton até o momento em que realmente precisamos dela. Isso é chamado de “lazy initialization”.

C#
public class Singleton
{
    // Variável estática que armazena a única instância do Singleton
    private static Singleton instance;
    
    // Objeto de controle de acesso à instância do Singleton
    private static readonly object lockObject = new object();
    
    // Propriedade para acessar a instância do Singleton
    public static Singleton Instance
    {
        get
        {
            // Verifica se a instância ainda não foi criada
            if (instance == null)
            {
                // Utiliza o objeto de controle de acesso para garantir que apenas uma thread possa criar a instância
                lock (lockObject)
                {
                    // Verifica novamente se a instância ainda não foi criada, pois outra thread pode ter criado enquanto aguardava o lock
                    if (instance == null)
                    {
                        // Cria a instância do Singleton
                        instance = new Singleton();
                    }
                }
            }
            
            // Retorna a instância do Singleton
            return instance;
        }
    }
    
    // Construtor privado para evitar a criação direta do Singleton
    private Singleton()
    {
        // Inicialização do Singleton
    }
}

// Fonte: ChatGPT

Neste exemplo, utilizamos a técnica de “lazy initialization” para criar a instância do Singleton somente quando ela for necessária. A propriedade Instance é responsável por retornar a instância existente ou criar uma nova instância se ela ainda não tiver sido criada. O objeto lockObject é utilizado para controlar o acesso concorrente à criação da instância, garantindo que apenas uma thread possa criar o Singleton.

É importante ressaltar que essa implementação com lazy initialization é thread-safe, ou seja, garante que apenas uma instância do Singleton será criada mesmo em ambientes com múltiplas threads.

Exemplos de Uso do Padrão Singleton

Uso em Gerenciadores de Conexão

Gerenciadores de conexão são um exemplo clássico de uso do padrão Singleton. Eles gerenciam um recurso que é caro para criar e manter, e onde normalmente só precisamos de uma instância.

Uso em Loggers

Loggers que escrevem em um arquivo ou enviam mensagens para um servidor também são comumente implementados como Singletons. Eles agregam todos os logs em um único local, facilitando a análise e depuração.

Uso em Configurações do Sistema

As classes de configuração do sistema que mantém um conjunto de parâmetros que podem ser acessados globalmente também são um bom exemplo de uso do Singleton.

Vantagens e Desvantagens do Padrão Singleton

Como todo padrão de design, o Singleton tem suas vantagens e desvantagens. Ele é útil quando precisamos garantir que apenas uma instância de uma classe exista, mas pode ser problemático quando usado indevidamente, especialmente em ambientes multithread.

Considerações Finais

O padrão Singleton é uma ferramenta poderosa em nosso arsenal de design de software. Como com qualquer ferramenta, devemos usá-la sabiamente e entender bem seus prós e contras antes de aplicá-la.

Esse conteúdo é parte do material disponibilizado para os participantes do meu grupo de estudos de Padrões de Projeto. Você quer participar desse grupo? Clique aqui e veja como funciona.

Dúvidas Frequentes

O padrão Singleton é considerado uma má prática?
Não, o padrão Singleton não é uma má prática, mas deve ser usado com cuidado, pois pode levar a problemas se usado incorretamente.

O padrão Singleton pode ser usado em aplicativos multi-thread?
Sim, mas precisa ser implementado corretamente para evitar condições de corrida.

Singleton e Global são a mesma coisa?
Não, embora ambos forneçam acesso global, Singleton garante uma única instância, enquanto uma variável global não.

Posso ter mais de um Singleton em minha aplicação?
Sim, você pode ter vários tipos diferentes de Singletons em sua aplicação.

O que é “lazy initialization” em Singleton?
Lazy initialization” é a técnica de adiar a criação da instância Singleton até o momento em que ela é realmente necessária.

Quer se aprofundar neste tema?

Então participe do grupo de estudos de Padrões de Projeto.

Desenvolva soluções simples para os problemas mais complexos. Escreva código fácil de entender, mais barato para manter e evoluir.

Participe do
grupo intensivo de

Padrões de Projeto

com

Desenvolva soluções simples para os problemas mais complexos. Escreva código fácil de entender, mais barato para manter e evoluir.

Participe do
grupo intensivo de

Padrões de Projeto

com

Desenvolva soluções simples para os problemas mais complexos. Escreva código fácil de entender, mais barato para manter e evoluir.

Veja outros artigos relacionados

Quer Melhorar Seu Design? Aplique CQS

Nesse mundo cada vez mais acelerado da tecnologia da informação, uma das metas constantes para desenvolvedores é a otimização e...

Você Precisa Conhecer o State Pattern

Em minha jornada como desenvolvedor de software, a descoberta e compreensão do State Pattern foi um divisor de águas, assim...

Como padrões ajudam a reduzir o impacto da escassez de recursos

Quando pensamos em software development, um dos grandes desafios é criar sistemas eficientes especialmente em ambientes com recursos limitados. Diante...

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de DDD do Jeito Certo:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Reputação e Marketing Pessoal:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Reputação e Marketing Pessoal:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Padrões de Projeto:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Padrões de Projeto:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Algoritmos e Estruturas de Dados:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Algoritmos e Estruturas de Dados:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Programa ElemarJR de Aceleração, Do Jeito Certo:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Programa ElemarJR de Aceleração, Do Jeito Certo:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Reputação e Marketing Pessoal:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Reputação e Marketing Pessoal:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Padrões de Projeto:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Padrões de Projeto:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de DDD do Jeito Certo:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de DDD do Jeito Certo:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Algoritmos e Estruturas de Dados:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Algoritmos e Estruturas de Dados:

Mentoria em Arquitetura de Software

Ênfase em Systems Design

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Reproduzir vídeo

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no curso de Padrão de design Singleton: Implementação e Exemplos de Uso:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no curso de Padrão de design Singleton: Implementação e Exemplos de Uso:

Padrão de design Singleton: Implementação e Exemplos de Uso

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Reputação e Marketing Pessoal:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no curso de Padrão de design Singleton: Implementação e Exemplos de Uso:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de DDD do Jeito Certo:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Padrões de Projeto:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Algoritmos e Estruturas de Dados:

× Precisa de ajuda?