Desenvolvimento - C#

Singleton - Padrão de Projeto com Microsoft .NET C Sharp

Veja neste artigo uma abordagem sobre o padrão de projeto singleton. Entenda como garantir que uma classe tenha somente uma instância e um único ponto de acesso.

por Flávio Secchieri Mariotti



Introdução

Padrão de Projeto ou em inglês Design Patterns, é uma forma organizada de criar soluções reutilizáveis para os problemas recorrentes do dia a dia de um projetista ou programador.

Por que usar Padrão de Projeto?

É possível desenvolver software sem utilizar padrões de projetos, e o fato de usar não característica um código ou software de qualidade. Padrão de projeto é somente um dos vários detalhes que compõem o desenvolvimento de um software. Usar padrões de projetos é uma escolha que cabe a cada desenvolvedor/time. Existem casos onde as empresas desenvolvem seus próprios padrões e suas framework de trabalho.

O conceito padrão de projeto foi criado na década de 70 pelo arquiteto e matemático Christopher Alexander um australiano que foi um dos principais críticos da arquitetura moderna. Alexander definiu dois pontos fundamentais para criação de um padrão, apontando as características e formato básico que um "objeto" deve conter para ser classificado como padrão:

Características

  • Encapsulamento
  • Generalidade
  • Equilíbrio
  • Abstração
  • Abertura
  • Combinatoriedade

Formato

  • Nome
  • Exemplo
  • Contexto
  • Problema
  • Solução

Embora o que Christopher Alexander estivesse propondo fosse padrões para construções civis, podemos perceber a total relação com o desenvolvimento de software. Portanto, podemos compreender o que é necessário para criação de um padrão.

Com isso, vamos então entender quais os benefícios e vantagens que ao desenvolver software utilizando padrões de projetos o time de desenvolvimento pode obter.

Singleton - Padrão de Projeto

O padrão de projeto singleton tem como definição garantir que uma classe tenha somente uma instância e fornecer um ponto global de acesso a mesma. Para isso, singleton implementa uma operação chamada de Instance que tem como premissa permitir que seus clientes acessem sua única instância, além de ser capaz de criar sua própria instância única.

Classificação

Padrões de projeto descreve 23 modelos de desenho, porém, cabe ressaltar que existem centenas de padrões. No famoso livro Design Patterns dos autores Gamma, Helm, Johnson e Vlissides é apresentado 23 padrões de projeto, documentados e já conhecidos no mundo do desenvolvimento de software. É importante lembrar que isso não significa que esses padrões são os mais úteis para se implementar, sendo assim, vale a pena pesquisar padrões em outras fontes.

Estes 23 padrões são divididos em padrões de criação, padrões estruturais e padrões comportamentais. Vamos explorar os 23 padrões de projeto na serie de artigos sobre o assunto. O padrão de projeto Singleton está classificado como padrão de criação.

Vantagens e perigos ao implementar Singleton

Benefícios:

  • Acesso controlado à instância única
  • Espaço de nomes reduzido
  • Permite um refinamento de operações e da representação
  • Permite um número variável de instâncias
  • Mais flexível do que operações de classes

Perigos ao implementar singleton de maneira incorreta:

  • Estado global
  • Utilização de singleton desnecessários
  • Anti-padrões para muitos programadores
  • Reversão difícil
  • Mais complexidades nos testes
  • Pode ser facilmente quebrado

Listagem 1: Exemplo código - Singleton Simples

Vamos agora criar uma classe que implementa o modelo simplificado do padrão Singleton. Para isso, vamos desenvolver uma classe que implementa o objeto "Cadeiras" que serão alocadas para um determinado jantar.

namespace Singleton
{
    // Classe no modelo Singleton simples
    public sealed class Cadeira
    {
        private static readonly Cadeira instance = new Cadeira();
        public int Quantidade { get; set; }

        private Cadeira() { }

        public static Cadeira Instance
        {
            get
            {
                return instance;
            }
        }
    }
    
    // Implementação a casse Singleton simples...
    class Program
    {
        static void Main(string[] args)
        {
            // Colocando em prática
            Cadeira _cadeira1 = Cadeira.Instance;
            _cadeira1.Quantidade = 1;

            Cadeira _cadeira2 = Cadeira.Instance;
            _cadeira2.Quantidade = 5;

            Console.WriteLine(_cadeira1.Quantidade.ToString());
            Console.WriteLine(_cadeira2.Quantidade.ToString());
            Console.ReadLine();
        }
    }
}

Com essa implementação podemos identificar que existe uma única instância e um único pronto de acesso, evitando a criação desnecessária de instâncias com um único ponto de acesso.

Listagem 2: Exemplo de código - Singleton com Generics

Outro recurso importante suportado pelo .Net Framework são os tipos generics. A implementação de uma classe singleton utilizando generics permite ao desenvolvedor mais flexibilidade no desenvolvimento do seu código. Para isso, é apresentado um código abaixo que implementa singleton utilizando generics com o mesmo exemplo do modelo apresentado acima, porém agora o cliente poderá alugar "cadeiras" e "mesas" para o seu jantar.

namespace Singleton
{
    public sealed class Singleton<T> where T : class, new()
    {
        private static T instance;

        public static T Instance()
        {
            lock (typeof(T))
                if (instance == null) instance = new T();

            return instance;
        }
    }

    public class Cadeira
    {
        public int Quantidade { get; set; }
    }

    public class Mesa
    {
        public string Tamanho { get; set; }
    }

    // Implementação a casse Singleton sincronizada...
    class Program
    {
        static void Main(string[] args)
        {
            // Colocando em prática
            Cadeira _cadeira = Singleton<Cadeira>.Instance();
            _cadeira.Quantidade = 5;

            Mesa _mesa = Singleton<Mesa>.Instance();
            _mesa.Tamanho = "10metros";

            Console.WriteLine(_cadeira.Quantidade.ToString());
            Console.WriteLine(_mesa.Tamanho);
            Console.ReadLine();
        }
    }
}

Listagem 3: Exemplo de código - Singleton Sincronizado

O padrão singleton também pode ser customizado para trabalhar de forma sincronizada, conforme exemplo abaixo:

public class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                    lock (typeof(Singleton))
                        if (instance == null) instance = new Singleton();

                return instance;
            }
        }
    }

Dicas

Para saber mais sobre como implementar o padrão singleton com C#, acesse: http://msdn.microsoft.com/en- us/library/ff650316.aspx

Conclusão

Aprendemos então com esse artigo, como implementar o padrão singleton e alcançar seus benefícios para o desenvolvimento de um código limpo e seguro. Singleton pode ser implementado de várias formas, conforme apresentado com diferentes exemplos neste artigo. Porém, sua utilização exige cuidados e responsabilidades para utilizá-lo de forma correta e coerente.

Portanto, com mais um artigo da seria padrões de projeto, podemos dizer com segurança que se utilizados com eficácia, são ferramentas poderosas no desenvolvimento de sistemas robustos e flexíveis.

Comunicado Importante

Espero que tenham gostado do conteúdo explorado neste artigo. Caso exista qualquer dúvida relacionada ao conteúdo ou interesse em conhecer um pouco mais sobre padrão de projeto Singleton, informe seu interesse usando o recurso de "comentários".

Referência

Steven John Metsker. Design Patterns in C#, Addison-Wesley Professional, 2004.

Erich Gramma; Richard Helm; Ralph Johnson; John Vlissides. Design Patterns Elements of Reusable Object-Oriented Software, Addison-Wesley Professional, 1994.

Flávio Secchieri Mariotti

Flávio Secchieri Mariotti - Especialista em Engenharia e Arquitetura de Software. Pós Graduado pelo Instituto de Pesquisa Avançada de Tecnologia IBTA em Engenharia de Software baseado em SOA. Bacharel em Sistemas de Informação pela UNIUBE e técnico em Processamento de Dados pela FEB. Consultor independente no desenvolvimento de software em arquitetura OO, SOA, GIS e Plataforma .NET.