Pergunta

A variável global glorificado - torna-se uma classe mundial gloried. Alguns dizem que quebrar design orientado a objetos.

Dê-me cenários, além da boa logger velho onde faz sentido usar o singleton.

Foi útil?

Solução

Em minha busca pela verdade eu descobri que há realmente muito poucas razões "aceitáveis" para usar um Singleton.

Uma das razões que tende a chegar a uma e outra vez sobre os internets é o de uma classe "logging" (que você mencionou). Neste caso, um Singleton pode ser usado em vez de uma única instância de uma classe porque uma classe de log precisa, geralmente, para ser usado repetidamente ad nauseam por todas as classes em um projeto. Se cada classe usa essa classe de log, injeção de dependência torna-se complicado.

Logging é um exemplo específico de um "aceitável" Singleton, porque ela não afeta a execução de seu código. logging Disable, a execução de código permanece o mesmo. Habilitá-lo, mesmo mesmo. puts Misko-lo na seguinte maneira em causa raiz de Singletons , "as informações aqui flui de uma maneira: a partir do aplicativo para o logger Mesmo que madeireiros são estado global, uma vez que flui sem informações de madeireiros em sua aplicação, madeireiros são aceitáveis.".

Estou certo de que há outras razões válidas também. Alex Miller, em " Patterns Eu Odeio ", fala de localizadores de serviço e cliente colaterais também sendo possivelmente escolhas "aceitáveis" de interface do usuário.

Leia mais em Singleton Eu te amo, mas você está me trazendo para baixo.

Outras dicas

A Singleton candidato deve preencher três requisitos:

  • controles de acesso simultâneo a um recurso compartilhado.
  • acesso ao recurso será solicitado a partir de várias partes, diferentes do sistema.
  • não pode haver apenas um objeto.

Se a sua proposta Singleton tem apenas um ou dois desses requisitos, uma reformulação quase sempre é a opção correta.

Por exemplo, um spooler de impressora é improvável de ser chamado de mais de um lugar (o menu de impressão), assim você pode usar semáforos para resolver o problema de acesso simultâneo.

Um logger simples é o exemplo mais óbvio de um Singleton possivelmente válido, mas isso pode mudar com esquemas de registro mais complexos.

Leitura arquivos de configuração que só deve ser lido no momento da inicialização e encapsulando-os em um Singleton.

Você usar um singleton quando você precisa para gerenciar um recurso compartilhado. Por exemplo, uma impressora de spooler. Sua aplicação deve ter apenas uma única instância do spooler, a fim de evitar conflito pedido para o mesmo recurso.

Ou uma conexão de banco de dados ou um gerenciador de arquivos etc.

Somente leitura singletons armazenar alguns estado global (idioma do usuário, ajuda filePath, caminho do aplicativo) são razoáveis. Tenha cuidado de usar singletons a lógica de negócios de controle - single quase sempre acaba sendo múltipla

A gestão de uma conexão (ou um pool de conexões) para um banco de dados.

Eu iria usá-lo também para recuperar e armazenar informações sobre arquivos de configuração externos.

Uma das maneiras que você usar um singleton é para cobrir um caso em que deve haver um único "broker" controlar o acesso a um recurso. Singletons são bons em loggers porque intermediar o acesso a, digamos, um arquivo, que só podem ser gravados exclusivamente. Para algo como extração de madeira, eles fornecem uma maneira de abstrair as gravações para algo como um arquivo de log - você poderia envolver um mecanismo de cache para o seu singleton, etc ...

Também pensar em uma situação onde você tem uma aplicação com muitas janelas / tópicos / etc, mas que precisa de um ponto único de comunicação. uma vez que eu usei um para controlar tarefas que queria meu aplicativo para iniciar. O singleton foi responsável pela serialização os postos de trabalho e exibir seu status a qualquer outra parte do programa que estava interessado. Neste tipo de cenário, você pode olhar para um singleton como sendo como uma espécie de classe "servidor" rodando dentro de sua aplicação ... HTH

A Singleton deve ser usado quando gerenciando o acesso a um recurso que é partilhado por toda a aplicação, e seria destrutivo para potencialmente ter várias instâncias da mesma classe. Certificar-se de que o acesso ao segmento seguro de recursos compartilhados é um muito bom exemplo de onde esse tipo de padrão pode ser vital.

Ao usar Singletons, você deve se certificar de que você não está acidentalmente esconder dependências. Idealmente, os singletons (como a maioria das variáveis ??estáticos em um aplicativo) ser configurado durante a execução de seu código de inicialização para o aplicativo (static void Main () para C # executáveis, static void main () para executáveis ??Java) e, em seguida, passou-se para todas as outras classes que são instanciado que exigem. Isso ajuda a manter a capacidade de teste.

Um exemplo prático de um singleton pode ser encontrada no Test :: Builder , a classe que faz quase todos os módulo de teste moderna Perl. O Test :: Builder Singleton lojas e corretores do estado e da história do processo de teste (os resultados dos testes históricos, conta o número de testes executados), bem como coisas como onde a saída de teste está indo. Estes são todos necessários para coordenar vários módulos de teste, escritos por diferentes autores, para trabalhar em conjunto em um script de teste único.

A história do solteirão de Test :: Builder é educacional. Chamando new() dá-lhe sempre o mesmo objeto. Primeiro, todos os dados foram armazenados como variáveis ??de classe com nada no próprio objeto. Isso funcionou até que eu queria testar Test :: Builder com ele mesmo. Então eu precisava de dois objetos Test :: Builder, uma configuração como um manequim, à captura e testar o seu comportamento e de saída, e um para ser o objeto de teste real. Nesse ponto Test :: Builder foi reformulado em um objeto real. O objeto singleton foi armazenado como dados de classe, e new() sempre devolvê-lo. create() foi adicionado para fazer um objeto fresco e permitir o teste.

Atualmente, os usuários estão querendo mudar alguns comportamentos de Test :: Builder em seu próprio módulo, mas deixar os outros sozinhos, enquanto os restos de história teste em comum em todos os módulos de teste. O que está acontecendo agora é o Teste monolítica :: Builder objeto está sendo dividido em pedaços menores (história, saída, formato ...) com uma instância de Test :: Builder coletá-los juntos. Agora Test :: Builder já não tem de ser um singleton. Seus componentes, como a história, pode ser. Isso empurra a necessidade inflexível de um singleton para baixo um nível. Dá mais flexibilidade ao usuário para misturar e combinar peças. Os objetos únicos menores agora podem apenas armazenar dados, com seus objetos contendo decidir como usá-lo. Ele ainda permite que uma classe não-Test :: Builder para jogar junto usando os singletons história e saída Test :: Builder.

Parece ser há um empurra e puxa entre a coordenação dos dados e flexibilidade de comportamento que podem ser mitigados, colocando o singleton em torno de apenas dados compartilhados com a menor quantidade de comportamento possível para garantir a integridade dos dados.

Quando você carrega uma configuração de propriedades do objeto, a partir do banco de dados ou um arquivo, ele ajuda a tê-lo como um singleton; não há nenhuma razão para manter os dados estáticos de releitura que não vai mudar enquanto o servidor está em execução.

Eu acho que o uso Singleton pode ser pensado como o mesmo que o relacionamento muitos-para-um em bancos de dados. Se você tem muitas partes diferentes de seu código que precisa trabalhar com uma única instância de um objeto, que é onde faz sentido singletons de uso.

Como todos disse, um recurso compartilhado -. Especificamente algo que não pode lidar com o acesso simultâneo

Um exemplo específico que eu tenho visto, é um escritor Lucene Pesquisa Index.

recursos compartilhados. Especialmente em PHP, uma classe de banco de dados, uma classe de modelo, e uma classe variável depósito global. Tudo tem que ser compartilhada por todos os módulos / classes que estão sendo usados ??em todo o código.

É um uso do objeto verdadeiro -> a classe de modelo contém o modelo da página que está sendo construído, e ele fica em forma, acrescentou, alteradas por módulos que estão adicionando a saída da página. Tem que ser mantido como uma única instância para que isso possa acontecer, eo mesmo vale para bancos de dados. Com um singleton banco de dados compartilhado, todas as classes de módulos podem ter acesso a consultas e levá-los sem ter que executar novamente eles.

Um singleton variável global depósito fornece-lhe um depósito variável global, confiável e facilmente utilizável. Ele arruma o seu código de um grande monte. Imagine ter todos os valores de configuração em uma matriz em um singleton como:

$gb->config['hostname']

ou ter todos os valores de idiomas em uma matriz como:

$gb->lang['ENTER_USER']

No final da execução do código da página, você tem, digamos, um agora amadurecer:

$template

Singleton, um Singleton $gb que tem a matriz lang para a substituição nele, e todas as saídas carregado e pronto. Você apenas substituí-los nas teclas que agora estão presentes no valor de página madura do objeto modelo, e depois servir-lo para o usuário.

A grande vantagem disso é que você pode fazer QUALQUER pós-processamento que você gosta em qualquer coisa. Você pode canalizar todos os valores de idioma para o Google Tradutor, ou de outra traduzir serviço e recuperá-los e substituí-los em seus lugares, traduzidos, por exemplo. Ou, você pode substituir em estruturas de páginas, ou, cordas de conteúdo, como você quer.

Você pode usar Singleton quando implementar o padrão do Estado (da maneira mostrada no livro GoF). Isso ocorre porque as classes do Estado de concreto não têm estado próprio, e executar suas ações em termos de uma classe de contexto.

Você também pode fazer Abstract Factory um singleton.

Pode ser muito pragmática às preocupações de infra-estrutura específica do configure como singletons ou variáveis ??globais. Meu exemplo favorito desta é estruturas de dependência de injeção que fazem uso de singletons para atuar como um ponto de conexão com o quadro.

Neste caso, você está tendo uma dependência da infra-estrutura para simplificar o uso da biblioteca e evitar complexidade desnecessária.

Eu usá-lo para uma linha de comando parâmetros objeto de encapsulamento quando se lida com módulos conectáveis. O programa principal não sabe o que os parâmetros de linha de comando são para os módulos que são carregados (e nem sempre sabe mesmo o que módulos estão sendo carregados). por exemplo, as principais cargas A, que não precisa de qualquer parâmetro em si (então por que deveria ter um ponteiro de cama / referência / whatever, não tenho certeza - parece que a poluição), em seguida, carrega módulos X, Y e Z. Dois destes, dizem X e Z, necessidade (ou aceitar) parâmetros, de modo que eles chamam de volta para o singleton de linha de comando para dizer-lhe quais os parâmetros para aceitar, e em tempo de execução que eles chamam de volta para descobrir se o usuário realmente tenha especificado qualquer deles.

De muitas maneiras, a exclusivo para a manipulação de parâmetros CGI iria funcionar da mesma forma se você estiver usando apenas um processo por consulta (outra mod_ * métodos não fizer isso, então seria ruim lá - assim, o argumento que diz você não deve usar singletons no mundo mod_cgi no caso de você porta para o mod_perl ou qualquer mundo).

Um exemplo com código, talvez.

Aqui, o ConcreteRegistry é um singleton em um jogo de poker que permite que os comportamentos todo o caminho até o acesso árvore de pacotes poucos, interfaces fundamentais do jogo (ou seja, as fachadas para o modelo, vista, controlador, meio ambiente, etc .):

http://www.edmundkirwan.com/servlet/fractal /cs1/frac-cs40.html

Ed.

1 - Um comentário sobre a primeira resposta:

Eu não concordo com uma classe Logger estático. isso pode ser prático para uma implementação, mas não pode ser substituível para testes de unidade. A classe estática não pode ser substituído por um ensaio duplo. Se não o fizer teste de unidade, você não vai não ver o problema aqui.

2 - Eu tento não criar um singleton com a mão. Eu só criar um objeto simples com construtores que me permitem injetar colaboradores para o objeto. Se eu precisava de um singleton, eu usaria um quadro de dependência inyection (Spring.NET, Unidade para .NET, Primavera para Java), ou algum outro.

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