Qual é a motivação por trás da anotação @ImplementedBy no Guice?

10

Li recentemente sobre a @ImplementedByanotaçã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 @ImplementedByanotaçã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 @ImplementedBycuidado; 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 @ImplementedByvalem 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 @ImplementedByanotação, a bind()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?

toniedzwiedz
fonte
2
Pergunta relacionada, possivelmente duplicada (embora seu título seja mais claro): O @ImplementedBy de Guice é mau?
22615 Jeff Bowman
Não é um duplicado estrito, mas tem havido alguma discussão interessante sobre isso aqui: stackoverflow.com/questions/6197178/...
Richard Vodden

Respostas:

8

Eu acho que o perigo aqui é usar apenas a @ImplementedByanotação. Utilizado adequadamente, em conjunto com as bind()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:

@ImplementedBy(NoOpDataService.class)
interface DataService {
    Map<String, MyPOJO> getData();
}

E então NoOpDataServiceé:

class NoOpDataService implements DataService {
    @Override
    public Map<String, MyPOJO> getData() {
        return Collections.emptyMap();
    }
}

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 DataServicenã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.

durron597
fonte
3
Adicionando código de teste à produção?
Basilevs