Desenvolvimento

21 dez, 2018

Arquitetura e desenvolvimento de software: Parte 6 – Singleton

Publicidade

E ai, pessoal! Tudo bem?

Continuando nossa série sobre design patterns, vamos ao último da lista de criacionais, o Singleton. Vamos lá?

Singleton

É um dos padrões mais simples, responsável por garantir que exista apenas uma instância de uma classe, garantindo uma declaração única e global de acesso ao objeto.

Alguns projetos necessitam que algumas classes tenham apenas uma instância. Por exemplo, em uma aplicação que precisa de uma infraestrutura de log de dados, pode-se implementar uma classe no padrão Singleton. Desta forma, existe apenas um objeto responsável pelo log em toda a aplicação que é acessível unicamente através da classe Singleton. Ou mesmo uma fila de elementos em uma aplicação Web. Todas as requisições devem obter elementos da mesma fila de forma ordenada e respeitando o semáforo.

Mas é algo que devemos utilizar com parcimônia, pois teremos nosso código acoplado a uma implementação específica.

Após a ficha resumo, teremos alguns exemplos extras em Java e Python, além do exemplo em C# na ficha resumo.

Ficha resumo

Vamos a ficha resumo do pattern, e logo em seguida, vou dar dois exemplos bem práticos do uso do Singleton. Vamos lá:

  • Nome: Singleton;
  • Objetivo / intenção: Garantir uma única instanciação de uma classe, com um ponto de acesso único e global;
  • Motivação: Existem classes que apenas uma instância de um objeto é o ideal; por exemplo, em uma aplicação que precisa de uma infraestrutura de log de dados, pode-se implementar uma classe no padrão Singleton, já que o acesso ao arquivo de log é serializado e economizamos memória com apenas uma alocação.
  • Aplicabilidade: Este padrão é muito utilizado para classes que precisamos de um único acesso global controlado ou que não temos porque criar várias instância, como um Logger, que irá afunilar o acesso ao arquivo de log. Ou mesmo em um sistema web que forneça itens para seus clientes vindos de uma fila.
  • Estrutura: Este padrão é apenas uma classe, que possui alguns métodos para garantir sua instância única. A forma de implementar isto varia de linguagem para linguagem, mas temos no geral esta representação:

  • Consequências: Este padrão permite o controle sobre como e quando os clientes acessam a instância e várias classes singleton podem obedecer uma mesma interface, permitindo, assim, que um singleton em particular seja escolhido para trabalhar com uma determinada aplicação em tempo de execução.
    Mas usando Singleton, você estará acoplando o seu código em uma implementação estática e específica e isso faz o seu código dependente dessa classe e impede, por exemplo, criar mocks em testes unitários. Em algumas linguagens, temos uma falsa segurança, como no Java, onde por exemplo, não existe uma classe apenas por JVM. O conceito de carregamento de classes em Java é feito por ClassLoader;
  • Implementações: Abaixo temos um exemplo simples de um Singleton em C#, mas teremos dois exemplos extras após o resumo:
using System;

public class MyClass
{
   private static volatile MyClass _instance;

   private MyClass() {}

   public static MyClass Instance
   {
      get
      {
         if (_instance == null)
         {
            _instance = new MyClass();
         }
         return _instance;
      }
   }
}
  • Usos conhecidos: Criação de logs, acesso a um banco de dados ou mesmo um gerenciador de fila para fornecer itens (cliente ou outro tipo de entidade) a diferentes requisições de forma organizada e única.
  • Padrões relacionados: Abstract Factory, Factory Method, Prototype e Builder;

Exemplos extras

Temos abaixo um exemplo extra, utilizando Python:

class Singleton:
    # Armazenamos a instancia nesta variavel
    __instance = None

    @staticmethod
    def getInstance():
        if Singleton.__instance == None:
            Singleton()
        return Singleton.__instance 

    def __init__(self):
        if Singleton.__instance != None:
            raise Exception("This class is a singleton!")
        else:
            Singleton.__instance = self

E neste outro exemplo, demonstramos um Singleton em Java. A partir da versão 1.5 do Java, a melhor abordagem utilizada para a definição de tipos Singleton é com a utilização de tipos Enum:

public enum Singleton
{
  INSTANCE;
  // não há necessidade de construtor privado
  // não há necessidade de getInstance, é só usar Singleton.INSTANCE
  
  public void DoWork() {
    System.out.println("Work");
  }
}

Concluindo

Este foi o padrão Singleton. De forma simples, ele se resume a garantir uma instanciação única de uma classe, sendo que todos as requisições vão acessar e competir pela mesma instância.

Na próxima parte desta série, vamos iniciar o grupo de padrões estruturais, começando pelo Adapter.

Como sempre, aguardo feedbacks e dúvidas de vocês! Até mais!