Design Patterns – Singleton – Parte 3

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (3)  (0)

Continuando com a série Design Patterns vamos falar sobre Singleton. Antes de começar a despejar um monte de informação, vamos criar um cenário... Você é um programador solo, que cria o projeto, trabalha sozinho em todos os passos do mesmo?

Continuando com a série Design Patterns vamos falar sobre Singleton.

Antes de começar a despejar um monte de informação, vamos criar um cenário...

Você é um programador solo, que cria o projeto, trabalha sozinho em todos os passos do mesmo? Ou você trabalha com uma equipe com vários programadores e cada um cria uma parte do projeto visando um todo para chegar a um único resultado? Em ambos os caso o singleton será útil, no primeiro vai resolver os casos dos programadores que esquecem até mesmo os próprios conceitos utilizados na implementação de uma classe, e no segundo vai garantir que ninguém vai criar mais de um objeto da mesma classe, vamos ver por quê?

Para alegria geral na nação, o padrão singleton é o mais simples em termos de seu diagrama de classe, na verdade o diagrama só contém uma classe.

Digamos que temos uma classe qualquer que chamaremos de Singleton e queremos que em toda a aplicação só exista uma única instância dessa mesma classe, e que você tenha que garantir que isso aconteça, no caso de ser um programador solo, de que você não se esqueça disso e no caso de uma equipe, que ninguém viole essa regra, bem com o padrão de projeto Singleton garantiremos uma única instância para a classe em questão.

Vamos analisar uma criação de uma classe singleton clássica não thread safe


public class Singleton

{

    private static Singleton _unicaInstancia;

    public int _valor { get; set; }

    // Outras variáveis e propriedade aqui

    // Contrutor privado

    private Singleton() { }

    public static Singleton getInstance()

    {

        if (_unicaInstancia == null)

        {

            _unicaInstancia = new Singleton();

        }

        return _unicaInstancia;

    }

    public void ExibirValor()

    {

        Console.WriteLine(_valor);

    }

    // Outros metodos aqui

}

Observe que o construtor é privado não permitindo a criação da classe de fora dela, e que temos um método getInstance que tem é estática e é esse mesmo método que verifica se o objeto _unicaInstancia que também deve ser estática já foi instanciado ou se é necessario criar a instancia e retorna o mesmo para a invocação do método, vamos ver um exemplo utilizando essa classe.

using System;

class SingletonClient

{

    static void Main(string[] args)

    {

        Singleton singCliente1 = Singleton.getInstance();

  singCliente1._valor = 10;

  Singleton singCliente2 = Singleton.getInstance();

        singCliente2.ExibirValor();

  singCliente2._valor = 20;

        singCliente1.ExibirValor();

        Console.ReadKey();

    }

 }

Vamos observar as linhas das criações dos objetos singCliente1 e singCliente2, veja que não utilizamos o new para criações das classes e sim solicitamos ao método getInstance da classe a única instancia dela. Setamos um valor para a propriedade _valor do singCliente1 e somente depois criamos o objeto singCliente2 e invocamos o método ExibirValor do objeto singCliente2, em seguida setamos um valor para a propriedade _valor do singCliente2 e invocamos o método ExibirValor do objeto singCliente1.

O resultado na tela do console vai ser:


Por que isso ocorreu se setamos o valor 10 no objeto singCliente1 e não setamos nada no singCliente2 e ele exibiu o valor do objeto singCliente1?

Bem, ocorre que ambos os objetos é uma referência o objeto estático que está dentro da classe, esse objeto é o único objeto instanciado em todo o projeto, o que foi feito, foi criar um ponto global de acesso a esse objeto.

Como foi dito a solução acima não vai ter o resultado esperado quando utilizado em MultiThreading, mais não se preocupe, vamos ver uma outra solução bem parecida com essa, na verdade algumas alterações feitas somente e já teremos uma classe singletam thread safe que poderá ser usada em varias threads.

using System;

using System.Threading;

 

public class Singleton

{

    // Responsável pela criação do objeto singleton

    class CriaInstancia

    {

        internal static readonly Singleton instancia = new Singleton();

    }

 

    public int _valor { get; set; }

 

    private Singleton() { }

 

    public static Singleton getInstance()

    {

        return CriaInstancia.instancia;

    }

 

    public void ExibirValor()

    {

        Console.WriteLine(_valor);

    }

}

 

class Program

{

    static void Main(string[] args)

    {

        Singleton singCliente1 = Singleton.getInstance();

        singCliente1._valor = 10;

        //Nova thread

        Thread teste = new Thread(TesteThread);

        teste.Start();

        teste.Join();

        //Final thread

        Singleton singCliente2 = Singleton.getInstance();

        singCliente2.ExibirValor();

        singCliente2._valor = 20;

        singCliente1.ExibirValor();

        Console.ReadKey();

    }

 

    private static void TesteThread()

    {

        Console.WriteLine("Inicio Thread");

        Singleton singCliente3 = Singleton.getInstance();

        singCliente3.ExibirValor();

        singCliente3._valor = 100;

        Console.WriteLine("Fim Thread");

    }

}

 

Resultado:


Close do código:

Foi adicionado na classe Singleton a classe CriaInstancia que agora contém a única instancia da classe Singleton com os modificadores internal, static e readonly permitindo assim que em qualquer thread seja utilizado o mesmo objeto.

// Responsável pela criação do objeto singleton

class CriaInstancia

{

    internal static readonly Singleton instancia = new Singleton();

}

A classe Singleton não tem mais o objeto statico da sua classe que servia para instanciar o objeto caso fosse a primeira solicitação. Com estas simples alterações garantiremos que em todas as threds criadas no sistema vamos ter o resultado esperado, uma única instância do objeto.

Caso você queira um construtor para o CriaInstancia você deverá cria-lo com o modificador static ficando desta forma:

class CriaInstancia

{

    internal static readonly Singleton instancia = new Singleton();

    static CriaInstancia()

    {

        instancia._valor = 200;

    }

}

Finalizamos mais este artigo, espero ter alcançado meus objetivos que erá passar um pouco do conceito do design pattern singleton de forma clara e com um facil entendimento.

Estarei falando sobre outros padrões nos proximos artigos.

Fontes:

FREEMAN, ERIC & FREEMAN, ELISABETH – Use a Cabeça! Padrões de Projetos (Design Patterns), 2ª Edição [http://www.livrariasaraiva.com.br/produto/1995765/]

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?