Li recentemente sobre a @ImplementedBy
anotação disponível no Google Guice . Ele permite que o programador especifique uma ligação entre uma interface e sua implementação para uso futuro em injeção de dependência. É um exemplo de ligação just-in-time .
Estou bastante acostumado a definir ligações explícitas nos meus módulos, usando a seguinte sintaxe:
bind(SomeInterface.class).to(SomeInterfaceImplementation.class);
De acordo com a documentação, isso é equivalente ao seguinte uso da @ImplementedBy
anotação:
@ImplementedBy(SomeInterfaceImplementation.class)
public interface SomeInterface {
//method declarations
}
O único ganho que posso ver aqui é que o código é marginalmente mais curto. Ao mesmo tempo, essa abordagem tem uma desvantagem apontada corretamente pelos mesmos documentos:
Use com
@ImplementedBy
cuidado; ele adiciona uma dependência em tempo de compilação da interface para sua implementação.
Essa dependência pode não ser um problema em muitos casos, mas eu pessoalmente a vejo como um cheiro de código.
Quais casos de uso @ImplementedBy
valem a pena usar a anotação?
Uma maneira possível parece ser empregá-la no código de uma biblioteca ou estrutura. Conforme descrito nos documentos, a anotação pode fornecer uma ligação padrão facilmente substituída por uma explícita.
Se um tipo estiver em uma
bind()
instrução (como o primeiro argumento) e tiver a@ImplementedBy
anotação, abind()
instrução será usada. A anotação sugere uma implementação padrão que pode ser substituída por uma ligação.
Dessa forma, como desenvolvedor de uma biblioteca, posso fornecer aos meus usuários uma ligação pronta para uso que pode ser personalizada em algum lugar no código do cliente.
Essa é a única razão para a anotação existir? Ou há algo que estou perdendo? Posso ganhar alguma coisa usando-o em código que é apenas um aplicativo que cuida de alguma lógica de negócios e não de uma biblioteca / estrutura a ser estendida?
fonte
Respostas:
Eu acho que o perigo aqui é usar apenas a
@ImplementedBy
anotação. Utilizado adequadamente, em conjunto com asbind()
instruções do seu módulo e assim por diante, tudo bem.Ter uma implementação padrão é ótimo para teste; você não necessariamente precisa definir explicitamente uma injeção simulada toda vez que estiver testando uma classe que possui muitas dependências ou se tiver uma classe na qual muitas coisas dependem (para que você precise definir uma simulação sempre) )
Por exemplo, você pode ter uma classe:
E então
NoOpDataService
é:Você nunca usará isso no seu código real, obviamente; no seu módulo Guice, você vincularia uma implementação que realmente faz alguma coisa. Mas todos os testes em classes que são injetadas
DataService
não precisam mais ter uma ligação simulada.Eu concordo com você que ter suas interfaces depende da sua implementação pode ser um cheiro de código; mas também pode remover o código padrão para facilitar o teste. Não é um recurso difícil de implementar; e, embora exista um pequeno potencial de abuso, as conseqüências não podem ser muito ruins (um serviço é iniciado de surpresa) e não seria muito difícil de corrigir, mesmo que isso aconteça.
fonte