Você sabe usar Singleton?

Thiago Gambarra
gambarra
Published in
2 min readSep 14, 2019

Introdução

Os Design Patterns (Padrões de Projetos) são arquiteturas testadas para construir softwares orientados a objetos flexíveis e sustentáveis. Os padrões ajudam a reduzir substancialmente a complexidade do processo de design.

Um dos primeiros padrões de projetos que aprendemos é o Singleton principalmente por sua simplicidade e eficiência. Ele é comumente utilizado para controlar a concorrência de acesso a recursos compartilhados.

Abaixo segue um exemplo de sua implementação.

O exemplo acima é uma das formas mais simples de se implementar um Singleton. Criamos uma classe com o construtor privado e um método estático público que mantém apenas uma única instância de Person sempre que for solicitado.

Essa abordagem funciona na maioria dos casos contudo pode nos reservar algumas surpresas.

Mas qual problema do código acima?

Esta implementação não é Thread Safe, ou seja, num ambiente Multithreading pode ser que seja gerada mais de uma instância para Person. Isso ocorre porquê no momento que duas threads simultâneas estiverem fazendo chamadas ao método uma pode estar instanciando Person enquanto a outro executando a expressão de verificação. Como a Thread 1 ainda não terminou a instanciação a Thread 2 acaba iniciando uma nova instância. Com isso ao invés de termos apenas uma única instância do objeto Person teremos duas.

E como resolver esse problema?

Vamos fazer uma pequena alteração no código.

Veja que nesta implementação utilizamos o recurso de lock para um objeto estático na classe. Isso garante um encadeamento de solicitação pois o objeto só será liberado ao final da execução. Com isso, mesmo em um ambiente Multithreading garantimos que a chamada ao método Singleton será sequencial. Aguardando a liberação do bloqueio para executar a próxima chamada.

Segunda forma de garantir o Threadsafe

Uma segunda abordagem para garantir o Threadsafe, de forma simples, seria utilizando o código abaixo.

Construtores estáticos em C # são especificados para executar apenas quando uma instância da classe é criada ou um membro estático é referenciado e para executar apenas uma vez por AppDomain. Assim nunca ocorrerá o problema de mais de uma instância.

A diferença desta abordagem em relação a anterior está no carregamento tardio. Enquanto nesta abordagem o objeto Person é instanciado no [Startup] da nossa aplicação. No exemplo anterior este processo é feito somente quando alguma rotina acionar o método GetPersonThreadSafe.

Conclusão

A implementação deste padrão é muito simples contudo é importante conhecer as variações e saber aplicá-las de acordo com a arquitetura e ambiente computacional onde nossas aplicações serão executadas.

Espero que essa dica tenha sido útil. Em breve mais dicas simples que são úteis no dia a dia…

--

--

Thiago Gambarra
gambarra
Editor for

Engenheiro de Software com foco em arquitetura .net.