C# - Padrão Singleton (revisitado)
Neste artigo vou apresentar com o padrão de criação Gof Singleton. |
O padrão
Singleton é um padrão de criação que permite
garantir que uma classe tenha apenas uma instância fornecendo
um ponto de acesso global a essa instância.
Nesta definição
destacamos dois pontos no padrão Singleton :
1- Garantir que uma classe tenha somente uma instância.
Com isso nós podemos controlar o acesso a algum recurso compartilhado como por
exemplo um banco de dados
um arquivo, etc.
2- Fornecer um ponto de acesso global a essa instância.
Isso permite que você acesse um objeto de qualquer lugar do programa mas protege
a instância de ser sobrescrita
por outro código.
Essa é a intenção principal do padrão Singleton.
Diagrama UML
No diagrama UML
deste padrão temos a classe Singleton que que
declara um membro estático chamado instance do tipo
Singleton usado para tratar a referência a única instância da classe. Note que
ele é estático e privado.
A seguir temos um
construtor privado sem parâmetros chamado Singleton
de forma que ninguém consiga
instanciar essa classe somente a própria classe Singleton.
Depois temos
também um membro privado e estático do mesmo tipo da classe chamado
Instance. Esse membro que pode ser uma
propriedade ou um método dependendo da implementação. vai verificar se a
instância já foi iniciada.
Caso não tenha sido iniciada ele vai fazer a criação da instancia pela primeira
e única vez.
Então esses são os elementos do diagrama o UML do padrão Singleton.
Exemplos de uso do padrão Singleton
Como exemplo de usos deste padrão podemos destacar:
1- Podemos usar o
padrão Singleton para controlar a concorrência de acesso a recursos
compartilhados como por exemplo o acesso aos recursos de um banco de dados ou a
arquivos;
2- Quando você tem uma classe que é usada por várias partes do sistema e ela não
gerencia nenhum estado como arquivos de log onde estamos apenas realizando
operações de escrita em arquivo;
3- No compartilhamento de dados quando você deseja manter valores de
configuração comuns em um Singleton para que possam ser acessados por outras
partes da aplicação como por exemplo se você tiver quaisquer valores
constantes ou valores de configuração comum poderá mantê-los em um
Singleton para que eles possam ser lidos por outras partes da sua aplicação.
Quando podemos usar o padrão
Singleton
Podemos fazer uma
verificação respondendo algumas perguntas para ter uma ideia se podemos
considerar ou não usar o padrão:
1- Faz sentido a classe ter apenas uma instância ?
Se você responder SIM então o pode considerar usar padrão Singleton.
.
2- Voce vai usar o padrão Singleton para substituir
variável global ?
Se você responder SIM então o padrão Singleton não deve ser considerado
porque variáveis globais não são uma boa prática e devem ser evitadas.
Você não deve usar o Singleton para substituir variáveis globais ou para
funcionar como um acesso a variáveis globais.
3- A classe poderá ter mais de uma instância ?
Se você responder SIM então não tem sentido você usar o padrão porque a classe
vai ter mais de uma instância e usamos o Singleton justamente para obter apenas
ter uma única instância.
Aplicando o padrão Singleton
Veremos agora uma implementação básica do padrão Singleton em um projeto do tipo Console usando o .NET 5.0.
Vamos criar a classe Singleton com o código abaixo:
public class Singleton { private static Singleton instance;
private Singleton()
|
Aqui temos a
classe Singleton e nesta classe temos:
1- Um campo privado e estático do tipo Singleton
que garante o ponto de acesso global à instancia da classe
2- A seguir temos um construtor privado sem parâmetros e assim somente a classe
Singleton poderá acessar o construtor para poder criar a sua instância
3- Depois definimos um membro estático chamado Instance
do tipo da classe que retorna a instancia da sua própria classe. Aqui
usamos uma propriedade, e, ela verifica se a variável
instance já foi iniciada e caso não tenha sido criamos a instância de
Singleton (isso é feito na primeira e unica vez).
Esta seria a implementação padrão mais básica do Singleton.
Note que o construtor da classe Singleton esta oculto do código cliente, e a propriedade Instance é o único modo de obter o objeto Singleton.
Para verificar a implementação do padrão vamos incluir o código em destaque na classe Singleton:
using static System.Console; public class Singleton { private static Singleton instance;
private int numeroDeInstancias = 0; |
Agora na classe Program inclua no método Main o código a seguir:
static void Main(string[] args) { Console.WriteLine("##### Padrão Singleton #####\n"); Console.WriteLine("Tentando criar uma instância s1."); Singleton s1 = Singleton.Instance; Console.WriteLine("Tentando criar uma instância s2.\n"); Singleton s2 = Singleton.Instance; if (s1 == s2) |
Neste código estamos tentando criar duas instâncias da classe Singleton e a seguir comparando as duas instâncias s1 e s2.
Se elas forem iguais isso indica que na verdade temos apenas uma única instância criada caso contrário teremos duas instâncias distintas.
Executando o projeto teremos o resultado abaixo:
Vemos assim que na implementação somente podemos criar uma instância da classe
Singleton.
No entanto existe
um problema com esta implementação : Ela não é segura
para Threads.
Assim esta implementação não vai funcionar em um ambiente
Multihread. Veremos porque isso ocorre.
Isso ocorre pelo seguinte : Havendo mais de uma thread a avaliação
da existência da instância pode ocorrer simultaneamente e assim
poderão ser criadas duas instancias diferentes violando o padrão.
Assim essa implementação padrão não deve ser usada e na outra parte do artigo
iremos mostrar uma implementação mais robusta do padrão Singleton que pode ser
usada em um ambiente multithread.
Pegue o código
do projeto aqui :
Singleton1.zip
"Mas o fruto do Espírito é: amor, gozo, paz,
longanimidade, benignidade, bondade, fé, mansidão, temperança.
Contra estas coisas não há lei."
Gálatas 5:22,23
Referências:
NET - Unit of Work - Padrão Unidade de ...
NET - O padrão de projeto Decorator
NET - Padrão de Projeto Builder
C# - O Padrão Strategy (revisitado)
NET - O padrão de projeto Command
NET - Apresentando o padrão Repository