C# -  Singleton versus Static


 Hoje veremos qual a diferença entre o padrão Singleton e a palavra reservada static (muito usada para definir um método ou classe como estática) e quando usar cada recurso de forma apropriada.

Começando pelo começo...

Static

A palavra chave static faz com que os métodos de uma classe estejam associados a classe e não com uma instância particular da classe. Esses métodos se tornam acessíveis a partir da classe pois não precisam ser acessados através de uma instância da classe. Embora também possa ser acessado desta forma.

Com isto concluímos que membros declarados como static são membros da classe e não membros de instância. Logo podemos acessar membros declarados como static em uma classe sem criar uma instância da classe.

Lembre-se que uma classe estática não pode ser instanciada, nem herdada, a não ser por objetos da classe e não pode ter construtores de instância,

Singleton

Singleton é um padrão de projeto que garante que sua aplicação vai criar apenas uma instância da classe a qualquer momento. Os singletons têm uma propriedade estática que você deve acessar para obter a referência do objeto.

A classe que implementa o padrão Singleton é chamada classe Singleton e possui um construtor privado que cria a instância da classe.

Como fazemos para obter somente um única instância de uma classe ?

A resposta reside nem utilizar um método estático da classe. Assim uma classe Singleton deverá ter um método estático  que chama o construtor para criar um instância da classe e retornar esta instância para quem chamou o método estático.

Agora vamos ver um exemplo prático onde vamos comparar o comportamento de static com singleton.

Recursos usados:

Exemplo prático de Static e Singleton

Crie um novo projeto do tipo Console(.NET Framework) no VS 2017 Community com o nome de Singleton_Static :

A seguir vamos definir o código abaixo no arquivo Program.cs :

using System;
namespace Singleton_Static
{
    public class ClasseNormal
    {
        public int variavelClasseNormal;
    }
    public sealed class ClasseSingleton
    {
        static ClasseSingleton _instancia;
        public static ClasseSingleton Instancia
        {
            get { return _instancia ?? (_instancia = new ClasseSingleton()); }
        }
        private ClasseSingleton() { }
        public string Mensagem { get; set; }
    }
    static public class ClasseEstatica
    {
        private static readonly int variavelEstatica;
        // Construtor Static constructor é executado 
        // somente uma vez quando o tipo for usado.   
        static ClasseEstatica()
        {
            variavelEstatica = 1;
        }
        public static string ExibirValor()
        {
            return string.Format("O valor da variável estática é {0}", variavelEstatica);
        }
        public static string Mensagem { get; set; }
    }
    // código ao lado
 class Program
 {
        static void Main(string[] args)
        {
            //Classe Normal uso e instanciação
            var ClasseNormal = new ClasseNormal { variavelClasseNormal = 26 };
            Console.WriteLine("Uso da classe Normal: " + ClasseNormal.variavelClasseNormal);
            //Uso da classe estática
            string valorRetornado = ClasseEstatica.ExibirValor();
            Console.WriteLine("Uso da classe Static: " + valorRetornado);
            //Uso da classe Singleton
            var variavelSingleton = ClasseSingleton.Instancia;
            variavelSingleton.Mensagem = "Macoratti .net";
            Console.WriteLine("Uso da classe Singleton : " + variavelSingleton.Mensagem);
            //Teste para ver se as instâncias de Singleton são iguais
            var outraVariavelSingleton = ClasseSingleton.Instancia;
            Console.WriteLine("Verifcando se as instâncias são as mesmas : " 
                                + variavelSingleton.Equals(outraVariavelSingleton));
            Console.Read();
        }
    }

}

Aqui definimos :

  1. Uma classe normal :  ClasseNormal - Precisamos criar primeiro um objeto da classe(new) para poder usar suas propriedades e métodos;
  2. Uma classe estática : ClasseEstatica - Acessamos as propriedades e métodos pelo nome da classe (não precisamos criar uma instância da classe)
  3. Uma classe Singleton : ClasseSingleton - Criamos uma instância usando sua propriedade estática que sempre cria uma única instância da classe.

Nota: Observe que mesmo tentando criar mais de uma instância da classe Singleton as instâncias são iguais.

Resultado da execução do código cima :

As classes estáticas e as classes Singleton são basicamente usadas quando você deseja armazenar uma única instância de uma variável, assim os dados podem ser acessados globalmente em todo o seu aplicativo.

Antes de passar as considerações vamos elencar as principais diferenças das classes Singleton sobre as classes estáticas.

Diferenças entre Singleton e static

O padrão Singleton tem várias vantagens sobre as classes estáticas.

Um singleton permite uma classe para a qual há apenas uma instância persistente durante a vida útil de um aplicativo. Isso significa que ele criou uma instância única e essa instância (referência a essa instância) pode ser passada como um parâmetro para outros métodos e tratada como um objeto normal. Enquanto uma classe estática permite apenas métodos estáticos e você não pode passar a classe estática como parâmetro.

Um Singleton pode implementar interfaces, herdar de outras classes e permitir herança. Enquanto uma classe estática não pode herdar seus membros da instância. Portanto, o Singleton é mais flexível que as classes estáticas e pode manter o estado.

Um Singleton pode ser inicializado de forma tardia(Lazy) ou assíncrona e carregado automaticamente pelo .NET Framework CLR (common language runtime) quando o programa ou namespace que contém a classe for carregado. Enquanto uma classe estática é geralmente inicializada quando for carregada pela primeira vez e isso leva a possíveis problemas de carregadores de classes.

A classe Singleton segue os Princípios Orientados a Objetos, de modo que os singletons podem ser manipulados polimorficamente sem forçar seus usuários a assumir que existe apenas uma instância. Enquanto estática não pode.

Usar Singleton significa ter um objeto único no ciclo de vida do aplicativo, portanto, o escopo está no nível do aplicativo.

Usar Static implica em não ter nenhum ponteiro de objeto, portanto, o escopo está no nível do domínio do aplicativo. Além disso, ambos devem ser implementados para ser thread-safe.

Conclusão

Então qual a conclusão ???  Devo usar Singleton ou Static ?

Sendo extremamente rigoroso quanto ao paradigma da orientação a objetos, você deve evitar usar métodos estáticos (função procedural) e também evitar o padrão Singleton (variável/classe global, anti-padrão) pois ambos ferem um dos pilares da OOP que é o encapsulamento.

Então qual a solução adotar para resolver situações nais quais precisamos acessar um recurso de forma global ?

Considere a utilização da injeção de dependências que é um padrão de projeto SOLID.

E estamos conversados...

'Porque há um só Deus, e um só Mediador entre Deus e os homens, Jesus Cristo homem.'
1 Timóteo 2:5

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti