Singleton

Singleton é um padrão de projeto de software (do inglês Design Pattern). Este padrão garante a existência de apenas uma instância de uma classe, mantendo um ponto global de acesso ao seu objeto.

Diagrama UML de uma classe singleton.

Nota linguística: O termo vem do significado em inglês para um conjunto (entidade matemática) que contenha apenas um elemento.[1]

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.

Onde Usar

Quando você necessita de somente uma instância da classe, por exemplo, a conexão com banco de dados, vamos supor que você terá que chamar diversas vezes a conexão com o banco de dados em um código na mesma execução, se você instanciar toda vez a classe de banco, haverá grande perda de desempenho, assim usando o padrão singleton, é garantida que nesta execução será instânciada a classe somente uma vez. Lembrando que este pattern é considerado por muitos desenvolvedores um antipattern, então, cuidado onde for utilizá-lo.

Como fazer a implementação do Singleton

1. Deixar o construtor privado, pois assim ninguém deve conseguir instanciar a classe, apenas o próprio Singleton.

2. Criar um atributo privado e estático do mesmo tipo da classe (instance). Algumas linguagens não tipadas não irão precisar do tipo, caso do PHP, por exemplo.

3. Método getInstance() é o principal ponto da classe. Ele verifica se a variável instance já foi iniciada, caso não tenha sido, ele faz sua criação pela primeira e única vez.

4. Para fazer a conexão, devemos chamar o getInstance da seguinte forma: ClasseSingleton.getInstance().

Exemplos

Em Perl 5

Segue um exemplo em Perl 5 de uma das formas de implementar uma classe Singleton com a orientação a objetos nativa:

package Singleton {  our $_instance;# construtor  sub instance {      my $class = shift;# constrói $_instance caso seja undef      $_instance = bless {}, $class unless $_instance;      return $_instance  }}

Em Python 2.7

Segue um exemplo em Python 2.7 de uma das formas de implementar uma classe Singleton (Utilizando o __new__):

class Singleton(object):    _instance = None    def __new__(cls, *args, **kwargs):        if not cls._instance:            cls._instance = super(Singleton, cls).__new__(                                      cls, *args, **kwargs)        return cls._instance

Em C++

Segue um exemplo em C++ da implementação de uma classe Singleton:

 class MyClass {    private:       // atributo estático da "instância única"       static MyClass* instance = 0;       // construtor privado: não pode ser utilizado fora da classe       MyClass() {}    public:       // função-membro que retorna sempre a mesma instância do objeto       static MyClass& getInstance()       {          if (!instance) instance = new MyClass();          return *instance;       } };

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, tal como mencionado por Joshua Bloch em seu livro "Java Efetivo Segunda Edição Revisada". Observe um exemplo:

public class SingletonDuplaVerificacao {private static SingletonDuplaVerificacao instance;private SingletonDuplaVerificacao() {}public static SingletonDuplaVerificacao getInstance() {if(instance == null) {synchronized(SingletonDuplaVerificacao.class) {if(instance == null) {instance = new SingletonDuplaVerificacao();}}}return instance;}}    Como usar:         1: Deixar o construtor privado, assim evitando qualquer criar um NEW.        2: Atributos privados e Estatico do mesmo tipo da classe instance        3: Metodo getInstance();

Em um dos parágrafos do Item 3 do livro de Joshua Bloch, ele diz:

"Essa abordagem é funcionalmente equivalente à abordagem de campo público, exceto por ser mais concisa, fornecer o mecanismo de serialização facilmente e fornecer uma garantia sólida contra a instanciação múltipla, mesmo no caso de serialização sofisticada ou ataques de reflexão. Embora ela ainda tenha que ser amplamente adotada, um tipo enum com apenas um elemento é a melhor maneira de implementar um singleton."

Em C#

Segue um exemplo em C# da implementação de uma classe Singleton:

using System;public class MyClass{   private static MyClass instance;   private MyClass() {}   public static MyClass Instance   {      get      {         if (instance == null)         {            instance = new MyClass();         }         return instance;      }   }}

Em Delphi

Abaixo segue um exemplo de como implementar uma classe Singleton:

interfacetype  TSingleton= class  private    class var FInstance: TSingleton;    class function GetInstance: TSingleton; static;  public    class property Instance : TSingleton read GetInstance;  end;implementation  class function TSingleton.GetInstance: TSingleton;  begin    If FInstance = nil Then      FInstance := TSingleton.Create();//objeto instanciado através do Finstance    Result := FInstance;//retorna o objeto  end;

Em PHP

Aviso importante: Singleton em PHP é considerado um anti-pattern por causa da life cycle request/response que aplicações PHP normalmente utilizam.

<?phpnamespace DesignPattern\AntiPattern;class Singleton{ private static $instance;        /*** Evita que a classe seja instanciada publicamente.** @return void* /        private function __construct()        {        }        /*** Evita que a classe seja clonada.** @return void* /        private function __clone()        {        }        /*** Método unserialize do tipo privado para prevenir a* desserialização da instância dessa classe.** @return void* /        private function __wakeup()        {        }        /*** Testa se  instância definida na propriedade,* caso sim, a classe não será instanciada novamente.** @return DesignPattern\AntiPattern\Singleton* / public static function getInstance() { if (!isset(self::$instance)) { self::$instance = new self; } return self::$instance; }}

Em Ruby

require 'singleton'class Foobar    include Singletonend

Em VB.NET

 Public Class MyClass    Private Shared _instancia As MyClass    Private Shared objetoSincronia As New Object    Private Sub New()    End Sub    Public Shared Function getInstancia() As MyClass        If _instancia Is Nothing Then            SyncLock objetoSincronia                If _instancia Is Nothing Then _instancia = New MyClass            End SyncLock        End If        Return _instancia    End Function End Class

Em ActionScript 3

package{ public class ExemploSingleton { private static var instance:ExemploSingleton; public function ExemploSingleton(enforcer:SingletonEnforcer) : void { if (enforcer == null) throw new Error("Só pode haver uma instância de ExemploSingleton"); } public static function getInstance() : ExemploSingleton { if (instance == null) instance = new ExemploSingleton( new SingletonEnforcer ); return instance; } }}//Para bloquear o acesso ao constructor.class SingletonEnforcer {}

Em C# (utilizando Generics)

public sealed class GenericSingleton<T> where T : class, new(){    private static T _instance;    public static T GetInstance()    {        lock (typeof(T))        {            if (_instance == null)                _instance = new T();            return _instance;        }    }}// Teste do padrão Singletonpublic class Car { public int Color { get; set; } }public class Person { public string Name { get; set; } }class Program{    static void Main(string[] args)    {        Car car = GenericSingleton<Car>.GetInstance();        car.Color = 1;        Person per = GenericSingleton<Person>.GetInstance();        per.Name = "John";        Car car2 = GenericSingleton<Car>.GetInstance();        car.Color = 2;    }}

Obs: Esta solução não impede a criação de múltiplas instâncias das classes Car e Person. Como a classe genérica GenericSingleton obriga que as classes passadas no parâmetro T tenham um construtor público, é possível criar instâncias em qualquer trecho de código através de construções do tipo: Car car3 = new Car();.

Em Kotlin

Segue um exemplo de Singleton em Kotlin.

  public object Singleton {    public fun facaAlgumaCoisa() {      //Aqui será feito alguma coisa legal    }  }  // O singleton é usado assim:  Singleton.facaAlgumaCoisa()

Em Typescript

Segue um exemplo de Singleton em Typescript.

class MyClass {  private static instance: MyClass | undefined;  private constructor() {}  public static getInstance(): MyClass {    if (!this.instance) {      this.instance = new MyClass();      return this.instance;    } else {      return this.instance;    }  }}

Benefícios

  • Permite o controle sobre como e quando os clientes acessam a instância.
  • 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.
  • Com apenas uma implementação interna do singleton pode-se fazer com que o singleton crie um número controlado de instâncias.
  • É mais flexível que métodos estáticos por permitir o polimorfismo.

Contras

  • Acoplamento: Usando Singleton você estará acoplando o seu código em uma implementação estática e específica. Isso faz o seu código dependente dessa classe e impede, por exemplo, criar mocks em testes unitários.
  • Escopo: Se você por alguma razão decidir que para determinado componente da aplicação você precisa de outra implementação terá que alterar manualmente todas as classes.
  • Falsa segurança: No java, por exemplo, não existe uma classe apenas por JVM. O conceito de carregamento de classes em java é feito por ClassLoader.

Referências

Ver também