Pergunta

dizer que tenho uma classe chamada PermissionManager que só deve existir uma vez para o meu sistema e, basicamente, cumpre a função de gerenciar várias permissões para várias ações em minha aplicação. Agora eu tenho alguma classe no meu aplicativo que precisa ser capaz de verificar uma determinada permissão em um de seus métodos. construtor deste classe é atualmente público, ou seja usada por usuários de API.

Até um par de semanas atrás, eu teria simplesmente tinha minha classe chamar o seguinte em algum lugar pseudo-código:

     PermissionManager.getInstance().isReadPermissionEnabled(this)

Mas desde que eu tenho todos notaram aqui singletons odiando + este tipo de acoplamento, eu queria saber qual a melhor solução seria, uma vez que os argumentos que tenho lido contra singletons parece fazer sentido (, alta de acoplamento não testável, etc.) .

Assim que eu deveria realmente exigir que os usuários da API para passar em uma instância PermissionManager no construtor da classe? Mesmo que eu só quero uma única instância PermissionManager de existir para a minha aplicação?

Ou vou sobre esta tudo errado e deve ter um construtor não-pública e uma em algum lugar fábrica que passa no caso de PermissionManager para mim?


Informações adicionais Note que quando digo "Dependency Injection", eu estou falando sobre o DI Pattern ... Eu não estou usando qualquer estrutura DI como Guice ou Primavera. (... ainda)

Foi útil?

Solução

Se você estiver usando um quadro de dependência de injecção, em seguida, a maneira comum de lidar com isso, quer seja para passar em um objeto PermissionsManager no construtor ou ter uma propriedade do tipo PermissionsManager que os conjuntos de enquadramento para você.

Se isto não for possível, em seguida, com os usuários obtêm uma instância dessa classe através de fábrica é uma boa escolha. Neste caso, a fábrica passa a PermissionManager para o construtor quando ele cria a classe. Em seu aplicativo start-up, você criaria a única PermissionManager primeiro, em seguida, criar a sua fábrica, passando o PermissionManager.

Você está correto que é normalmente complicado para os clientes de uma classe para saber onde encontrar a instância PermissionManager correta e passá-lo em (ou até mesmo para se preocupar com o fato de que sua classe usa um PermissionManager).

Uma solução de compromisso que eu vi é para dar sua aula de uma propriedade do tipo PermissionManager. Se a propriedade tiver sido definida (por exemplo, em um teste de unidade), você usa essa instância, caso contrário você usar o singleton. Algo como:

PermissionManager mManager = null;
public PermissionManager Permissions
{
  if (mManager == null)
  {
    return mManager;
  }
  return PermissionManager.getInstance();
}

É claro que, a rigor, o seu PermissionManager deve implementar algum tipo de interface IPermissionManager, e é que sua outra classe deve referenciar assim uma implementação fictícia pode ser substituído mais facilmente durante o teste.

Outras dicas

Você pode realmente começar por injetar o PermissionManager. Isso fará com que sua classe mais testável.

Se isso causa problemas para os usuários dessa classe que você pode tê-los usar um método de fábrica ou uma fábrica abstrata. Ou você pode adicionar um construtor sem parâmetros que para eles a chamada que injeta o PermissionManager enquanto seus testes usar outro construtor que você pode usar para zombar do PermissionManager.

A dissociação entre as classes mais faz suas classes mais flexível, mas também pode torná-los mais difícil de usar. Ele depende da situação que você precisa. Se você só tem uma PermissionManager e não tenho nenhum problema testando as classes que usam isso, então não há nenhuma razão para usar DI. Se você quer que as pessoas para ser capaz de adicionar sua própria implementação PermissionManager então DI é o caminho a percorrer.

Se você estiver assinando a forma como injeção de dependência de fazer as coisas, o que quer que as classes precisam de sua PermissionManager deve tê-lo injetado como uma instância de objeto. O mecanismo que controla a sua instanciação (para reforçar a natureza Singleton) funciona a um nível superior. Se você usar um quadro de injeção de dependência como Guice, ele pode fazer o trabalho de aplicação. Se você estiver fazendo sua fiação objeto com a mão, favores de injeção de dependência agrupamento código que faz instanciação (novo trabalho do operador) longe de sua lógica de negócios.

De qualquer maneira, porém, o clássico "capital-S" Singleton é geralmente visto como um anti-padrão no contexto de injeção de dependência.

Essas mensagens têm sido esclarecedora para mim no passado:

Assim que eu deveria realmente exigir que os usuários da API para passar em uma instância PermissionManager no construtor da classe? Mesmo que eu só quero uma única instância PermissionManager de existir para a minha aplicação?

Sim, isso é tudo que você precisa fazer. Se uma dependência é um singleton / por solicitação / por fio ou um método de fábrica é de responsabilidade de seu recipiente e configuração. No mundo .net que teria idealmente a dependência de uma interface IPermissionsManager para reduzir ainda mais o acoplamento, eu supor que esta é a melhor prática em Java também.

O padrão Singleton não é ruim por si só, o que o torna feio é a forma como é comumente usado, como a exigência de apenas querendo uma única instância de uma determinada classe, o que eu acho que é um grande erro.

Neste caso eu faria PermissionManager uma classe estática a menos que por algum motivo você precisa que ele seja um tipo instanciable.

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