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

StackOverflow https://stackoverflow.com/questions/46541

  •  09-06-2019
  •  | 
  •  

Pergunta

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

Foi útil?

Solução

  • 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 caro de recursos 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, por isso é mais fácil de manter e resulta em um código melhor.

Outras dicas

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

  • Pode introduzir o estado global
  • Fique fortemente acoplado a várias outras classes
  • Ocultar dependências
  • Pode dificultar aulas de teste de unidade isoladamente

Em vez disso, olhe para Injeção de dependência e Inversão do Contêiner de Controle bibliotecas.Várias das bibliotecas IoC cuidarão do gerenciamento vitalício para você.

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

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


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

Uma das minhas discussões favoritas sobre esse assunto é aqui (site original fora do ar, agora vinculado a Máquina Wayback de Arquivo da Internet.)

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 subclasses diferentes
  • isso pode resultar em um aplicativo mais sustentável

Uma classe estática com uma carga de variáveis ​​estáticas é um pouco complicada.

/**
 * 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 está em SOMENTE 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 argumento.Isso permite que o código seja direcionado para o singleton "certo".Sabemos que você só vai precisar de um deles...até que você não faça isso.

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.

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.

Por outro lado, uma classe cheia de métodos estáticos é uma coleção de ações que você pode querer executar, 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 quando necessário.

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

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

MyStaticClass.GetInstance().DoSomething();

é essencialmente o mesmo que

MyStaticClass.DoSomething();

O que você realmente deveria estar fazendo é tratando 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 tratá-lo apenas como um objeto.

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

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();

contra

MySingleton.doSomething();

Os componentes internos do MySingleton obviamente serão diferentes entre eles, mas, deixando de lado as questões de segurança de thread, ambos terão o mesmo desempenho em relação ao código do cliente.

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

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

Praticamente qualquer exemplo de singleton mostra como não fazê-lo.

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

O código de limpeza parece mais natural quando você tem um singleton, em oposição a uma classe estática contendo campos de estado estáticos.

O código, no entanto, terá a mesma aparência de qualquer maneira, portanto, se você tiver motivos mais específicos para perguntar, talvez deva elaborar.

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

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

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 Singleton com base em algum contexto.

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

rp

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 for usado, ou nunca se seu singleton não for usado.Uma classe estática não teria essa inicialização automática.

Uma vez obtida uma referência a um objeto singleton, ela pode ser usada como qualquer outro objeto.O código do cliente pode nem precisar saber que 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

Obviamente, isso torna as coisas mais fáceis quando você escolhe abandonar o padrão Singleton em favor de um padrão real, como o IoC.

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

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

Um singleton também é uma boa ideia se você deseja forçar o armazenamento eficiente de dados em cache.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 cara análise de xml.Caso contrário, devolvo uma cópia do cache.Como ter vários caches significaria que ainda teria que carregar a mesma definição várias vezes, preciso ter um cache estático.Optei por implementar esta classe como um singleton para poder escrever a classe usando apenas membros de dados normais (não estáticos).Isso me permite ainda criar uma instanciação da classe caso eu precise dela por algum motivo (serialização, teste de unidade, etc.)

Singleton é como um serviço, como 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 de 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, assim como o Singleton pode ser construído com algumas variáveis ​​estáticas, você poderá compará-lo com 'goto'.Pode ser muito útil para construir outras estruturas, mas você realmente precisa saber como usá-lo e não deve “usá-lo demais”.Portanto, a recomendação geral é seguir o Singleton e usar estática, se necessário.

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

referir esse

resumo:

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

b.usar 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 (conjunto de conexões) ..etc.Para ter certeza de que não será instanciado várias vezes.Uma classe Singleton ajudará a evitar que tal caso aconteça

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

Por exemplo, criando um auxiliar em torno de uma classe de registro:Se você tiver uma seção mutável (usuário atual HKey vs.Máquina local HKEY) você poderia ir:

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

Agora, quaisquer outras chamadas para esse singleton operarão na seção Máquina Local.Caso contrário, usando uma classe estática, você teria que especificar todo o hive da Máquina Local ou ter um método como ReadSubkeyFromLocalMachine.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top