Quando você deve usar o padrão singleton em vez de uma classe estática? [fechadas]

85

Cite as considerações de design ao decidir entre o uso de um singleton e uma classe estática. Ao fazer isso, você é meio que forçado a contrastar os dois, então quaisquer contrastes que você possa encontrar também são úteis para mostrar seu processo de pensamento! Além disso, todo entrevistador gosta de ver exemplos ilustrativos. :)

cdleary
fonte
uma classe java não pode se tornar estática, a menos que seja uma classe interna
Harshana
1
Se o estado do objeto importa, então use singleton; caso contrário, use uma classe estática.
Levent Divilioglu

Respostas:

80
  • Singletons podem implementar interfaces e herdar de outras classes.
  • Singletons podem ser carregados lentamente. Somente quando for realmente necessário. Isso é muito útil se a inicialização incluir carregamento de recursos caro ou conexões de banco de dados.
  • Singletons oferecem um objeto real.
  • Singletons podem ser estendidos para uma fábrica. O gerenciamento de objetos nos bastidores é abstrato, portanto, é mais fácil de manter e resulta em um código melhor.
Tobias
fonte
2
Dê uma olhada neste link também: codeofdoom.com/wordpress/2008/04/20/…
Amit
4
"Singletons podem ser carregados lentamente" - em C #, o construtor estático só é chamado na primeira vez que um membro estático é referenciado. No PHP, você pode usar o carregamento automático para que seja executado apenas na primeira vez que a classe for usada.
mpen
As inicializações estáticas do Java também são lentas. Nenhum ponto para Singletons lá.
MikeFHay
13

Que tal "evitar os dois"? Singletons e classes estáticas:

  • Pode introduzir estado global
  • Fique intimamente ligado a várias outras classes
  • Ocultar dependências
  • Pode dificultar as aulas de teste de unidade isoladamente

Em vez disso, examine as bibliotecas de injeção de dependência e inversão de contêiner de controle . Várias das bibliotecas IoC cuidarão do gerenciamento vitalício para você.

(Como sempre, há exceções, como classes de matemática estáticas e métodos de extensão C #.)

TrueWill
fonte
1
Small nits: classes singleton são compatíveis com técnicas de injeção de dependência (apenas injete-as em suas classes dependentes e elas não precisam codificar nada) - isso permite simulação e teste de forma isolada. Eles também são um padrão de design válido para o gerenciamento de recursos que são conhecidos por serem limitados em toda a plataforma. (O exemplo clássico são as impressoras que não têm gerenciamento de contenção.)
cdleary
@cdleary - concordado; entretanto, a implementação clássica geralmente deixa Singleton.getInstance () em toda a base de código. "Singletons" para gerenciar recursos, caches, etc. podem ser implementados com estruturas POCOs / POJOs e IoC Container que suportam gerenciamento de tempo de vida (registre o tipo como tempo de vida do contêiner e cada resolução terá a mesma instância).
TrueWill
9
Se você quiser dar aos seus solteiros um enterro adequado, vá para singletonfuneralservice.com
TrueWill
1
Hide Dependenciesalgumas informações adicionais sobre este ponto: Você pode implementar o padrão Inversão de Controle, por exemplo, usando Ninject . Isso permite que você use apenas uma instância de um tipo vinculando-o a a SingletonScope, o que significa que ele vai injetar a mesma instância, mas a classe não será única.
LuckyLikey
8

Eu diria que a única diferença é a sintaxe: MySingleton.Current.Whatever () vs MySingleton.Whatever (). O estado, como David mencionou, é basicamente "estático" em ambos os casos.


EDIT: A brigada de enterro veio de digg ... de qualquer forma, pensei em um caso que exigiria um singleton. As classes estáticas não podem herdar de uma classe base nem implementar uma interface (pelo menos em .Net elas não podem). Portanto, se você precisar dessa funcionalidade, deverá usar um singleton.

xanadont
fonte
7

Uma das minhas discussões favoritas sobre esse assunto está aqui (site original fora do ar, agora vinculado ao Internet Archive Wayback Machine .)

Para resumir as vantagens de flexibilidade de um Singleton:

  • um Singleton pode ser facilmente convertido em uma fábrica
  • um Singleton pode ser facilmente modificado para retornar diferentes subclasses
  • isso pode resultar em um aplicativo mais sustentável
amanhecer
fonte
5

Uma classe estática com um monte de variáveis ​​estáticas é meio que um hack.

/**
 * Grotty static semaphore
 **/
 public static class Ugly {

   private static int count;

   public synchronized static void increment(){
        count++;
   }

   public synchronized static void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized static boolean isClear(){
         return count==0;    

    }
   }

Um singleton com uma instância real é melhor.

/**
 * Grotty static semaphore
 **/
 public static class LessUgly {
   private static LessUgly instance;

   private int count;

   private LessUgly(){
   }

   public static synchronized getInstance(){
     if( instance==null){
        instance = new LessUgly();
     }
     return instance;
   }
   public synchronized void increment(){
        count++;
   }

   public synchronized void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized boolean isClear(){
         return count==0;    

    }
   }

O estado é APENAS na instância.

Portanto, o singleton pode ser modificado posteriormente para fazer pooling, instâncias locais de thread, etc. E nenhum código já escrito precisa ser alterado para obter o benefício.

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(POOL_SIZE);
            for( int i=0; i < POOL_SIZE; i++){
               LessUgly instance = new LessUgly();  
               freePool.add( instance)
            }
         }
         LessUgly instance = session.get( Session.getSessionID());
         if( instance == null){
            instance = freePool.read();
         }
         if( instance==null){
             // TODO search sessions for expired ones. Return spares to the freePool. 
             //FIXME took too long to write example in blog editor.
         }
         return instance;
       }     

É possível fazer algo semelhante com uma classe estática, mas haverá sobrecarga por chamada no despacho indireto.

Você pode obter a instância e passá-la para uma função como um argumento. Isso permite que o código seja direcionado para o singleton "certo". Sabemos que você só precisará de um deles ... até não precisar.

O grande benefício é que singletons com estado podem se tornar thread-safe, enquanto uma classe estática não pode, a menos que você a modifique para ser um singleton secreto.

Tim Williscroft
fonte
4

Pense em um singleton como um serviço. É um objeto que fornece um conjunto específico de funcionalidades. Por exemplo

ObjectFactory.getInstance().makeObject();

A fábrica de objetos é um objeto que executa um serviço específico.

Em contraste, uma classe cheia de métodos estáticos é uma coleção de ações que você pode querer realizar, organizadas em um grupo relacionado (A classe). Por exemplo

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

O exemplo StringUtils aqui é uma coleção de funcionalidades que podem ser aplicadas em qualquer lugar. O objeto de fábrica singleton é um tipo específico de objeto com uma responsabilidade clara que pode ser criado e repassado onde necessário.

izb
fonte
4

As classes estáticas são instanciadas em tempo de execução. Isso pode ser demorado. Singletons podem ser instanciados apenas quando necessário.

dmo
fonte
13
Singletons são instanciados em tempo de execução também ...
recursivo
1
@recursive: a instanciação do singleton pode ser controlada.
Nikit Batale
3
talvez uma palavra melhor seria inicialização (ao invés de instanciação)
Marlon
3

Singletons não devem ser usados ​​da mesma maneira que classes estáticas. Em essência,

MyStaticClass.GetInstance().DoSomething();

é essencialmente o mesmo que

MyStaticClass.DoSomething();

O que você realmente deveria fazer é tratar o singleton como apenas mais um objeto . Se um serviço exigir uma instância do tipo singleton, passe essa instância no construtor:

var svc = new MyComplexServce(MyStaticClass.GetInstance());

O serviço não deve estar ciente de que o objeto é um singleton e deve tratar o objeto apenas como um objeto.

O objeto pode certamente ser implementado, como um detalhe de implementação e como um aspecto da configuração geral, como um singleton se isso tornar as coisas mais fáceis. Mas as coisas que usam o objeto não deveriam saber se o objeto é um singleton ou não.

Yfeldblum
fonte
2

Se por "classe estática" você quer dizer uma classe que possui apenas variáveis ​​estáticas, então elas realmente podem manter o estado. Meu entendimento é que a única diferença seria como você acessa essa coisa. Por exemplo:

MySingleton().getInstance().doSomething();

versus

MySingleton.doSomething();

As partes internas do MySingleton obviamente serão diferentes entre eles, mas, questões de thread-safety à parte, ambos terão o mesmo desempenho em relação ao código do cliente.

Programador Outlaw
fonte
2
Singletons são eles próprios objetos -> eles podem ser passados ​​como argumentos.
Christian Klauser
2

O padrão Singleton é geralmente usado para servir dados independentes ou estáticos da instância, onde vários threads podem acessar dados ao mesmo tempo. Um exemplo pode ser códigos de estado.

Mayank
fonte
1

Singletons nunca devem ser usados ​​(a menos que você considere uma classe sem estado mutável um singleton). "classes estáticas" não devem ter nenhum estado mutável, exceto talvez caches thread-safe e similares.

Praticamente qualquer exemplo de um singleton mostra como não fazer isso.

Tom Hawtin - tackline
fonte
4
E as classes de gerenciador que controlam os recursos de hardware? E as classes de arquivos de log?
RJFalconer
0

Se um singleton é algo que você pode descartar, para limpar depois, você pode considerá-lo quando for um recurso limitado (ou seja, apenas 1 dele) que você não precisa o tempo todo e tem algum tipo de memória ou custo do recurso quando alocado.

O código de limpeza parece mais natural quando você tem um singleton, ao contrário de uma classe estática contendo campos de estado estático.

O código, no entanto, terá a mesma aparência de qualquer maneira, então se você tiver razões mais específicas para perguntar, talvez você deva elaborar.

Lasse V. Karlsen
fonte
0

Os dois podem ser bastante semelhantes, mas lembre-se que o verdadeiro Singleton deve -se ser instanciado (concedido, uma vez) e, em seguida, servido. Uma classe de banco de dados PHP que retorna uma instância de mysqlinão é realmente um Singleton (como algumas pessoas a chamam), porque está retornando uma instância de outra classe, não uma instância da classe que tem a instância como um membro estático.

Portanto, se você estiver escrevendo uma nova classe da qual planeja permitir apenas uma instância em seu código, pode também escrevê-la como um Singleton. Pense nisso como escrever uma classe normal e adicionar a ela para facilitar o requisito de instanciação única. Se estiver usando a classe de outra pessoa que não pode ser modificada (como mysqli), você deve usar uma classe estática (mesmo se não conseguir prefixar sua definição com a palavra-chave).

Brian Warshaw
fonte
0

Singletons são mais flexíveis, o que pode ser útil nos casos em que você deseja que o método Instance retorne diferentes subclasses concretas do tipo do Singleton com base em algum contexto.

amanhecer
fonte
0

Classes estáticas não podem ser transmitidas como argumentos; instâncias de um singleton podem ser. Conforme mencionado em outras respostas, observe os problemas de encadeamento com classes estáticas.

rp

rp.
fonte
0

Um singleton pode ter um construtor e um destruidor. Dependendo do seu idioma, o construtor pode ser chamado automaticamente na primeira vez que seu singleton é usado, ou nunca se seu singleton não for usado. Uma classe estática não teria essa inicialização automática.

Assim que uma referência a um objeto singleton é obtida, ela pode ser usada como qualquer outro objeto. O código do cliente pode nem mesmo precisar saber se está usando um singleton se uma referência ao singleton for armazenada anteriormente:

Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton

Isso obviamente torna as coisas mais fáceis quando você opta por abandonar o padrão Singleton em favor de um padrão real, como IoC.

Landon Kuhn
fonte
0

Use o padrão singleton quando precisar computar algo em tempo de execução que você calcularia em tempo de compilação se pudesse, como tabelas de pesquisa.

Jared Updike
fonte
0

Acho que um lugar onde Singleton fará mais sentido do que a classe estática é quando você precisa construir um pool de recursos caros (como conexões de banco de dados). Você não estaria interessado em criar o pool se ninguém nunca os usar (classe estática significa que você fará o trabalho caro quando a classe for carregada).

Jagmal
fonte
0

Um singleton também é uma boa ideia se você deseja forçar o armazenamento em cache eficiente dos dados. por exemplo, tenho uma classe que procura definições em um documento xml. Como a análise do documento pode demorar um pouco, configurei um cache de definições (uso SoftReferences para evitar outOfmemeoryErrors). Se a definição desejada não estiver no cache, faço a análise de xml cara. Caso contrário, eu devolvo uma cópia do cache. Já que ter vários caches significaria que eu ainda teria que carregar a mesma definição várias vezes, eu preciso ter um cache estático. Eu escolhi implementar esta classe como um singleton para que eu pudesse escrever a classe usando apenas membros de dados normais (não estáticos). Isso me permite ainda criar uma representação da classe caso eu precise dela por algum motivo (serialização, teste de unidade, etc.)

KitsuneYMG
fonte
0

Singleton é como um serviço, conforme já mencionado. Pro é sua flexibilidade. Estático, bem, você precisa de algumas partes estáticas para implementar o Singleton.

Singleton possui código para cuidar da instanciação do objeto real, o que pode ser uma grande ajuda se você tiver problemas de corrida. Em uma solução estática, você pode precisar lidar com problemas de corrida em vários locais de código.

No entanto, da mesma forma que Singleton pode ser construído com algumas variáveis ​​estáticas, você pode compará-lo com 'goto'. Ele pode ser muito útil para construir outras estruturas, mas você realmente precisa saber como usá-lo e não deve "abusar" dele. Portanto, a recomendação geral é manter o Singleton e usar a estática se for necessário.

verifique também o outro post: Por que escolher uma classe estática em vez de uma implementação singleton?

Amegon
fonte
0

consulte isso

resumo:

uma. Uma regra fácil que você pode seguir é: se não for necessário manter o estado, você pode usar uma classe estática, caso contrário, deve usar um Singleton.

b. use um Singleton se for um objeto particularmente “pesado”. Se o seu objeto for grande e ocupar uma quantidade razoável de memória, muitas chamadas n / w (pool de conexão) ..etc. Para ter certeza de que não será instanciado várias vezes. Uma classe Singleton ajudará a evitar que tal caso aconteça

Santh
fonte
-1

Quando a única classe precisa de estado. Singletons mantêm um estado global, classes estáticas não.

Por exemplo, criando um ajudante em torno de uma classe de registro: Se você tiver hive alterável (HKey Current User vs. HKEY Local Machine), você pode ir:

RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine

Agora, qualquer outra chamada para aquele singleton irá operar na seção Máquina Local. Caso contrário, usando uma classe estática, você teria que especificar aquela seção da Máquina Local everytiem ou ter um método como ReadSubkeyFromLocalMachine.

David J. Sokol
fonte
1
Eu argumentaria contra o uso de um Singleton desta forma ... É muito perigoso manter os estados persistentes, porque o próximo chamador pode esquecer de definir a colméia e gravar no registro da seção errada ... :-( Isto é provavelmente um exemplo de uso indevido que faz as pessoas pensarem que