¿Cuál es la motivación detrás de la anotación @ImplementedBy en Guice?

10

Recientemente leí sobre la @ImplementedByanotación disponible en Google Guice . Permite al programador especificar un enlace entre una interfaz y su implementación para uso futuro en la inyección de dependencia. Es un ejemplo de un enlace justo a tiempo .

Estoy bastante acostumbrado a definir enlaces explícitos en mis módulos, usando la siguiente sintaxis:

bind(SomeInterface.class).to(SomeInterfaceImplementation.class);

De acuerdo con la documentación, esto es equivalente al siguiente uso de la @ImplementedByanotación:

@ImplementedBy(SomeInterfaceImplementation.class)
public interface SomeInterface {
    //method declarations
}

La única ganancia que puedo ver aquí es que el código es marginalmente más corto. Al mismo tiempo, este enfoque tiene un inconveniente señalado correctamente por los mismos documentos:

Usar con @ImplementedBycuidado; agrega una dependencia en tiempo de compilación de la interfaz a su implementación.

Tal dependencia puede no ser un problema en muchos casos, pero personalmente lo veo como un olor a código.

¿Qué casos de uso hacen que @ImplementedByvalga la pena usar la anotación?

Una posible forma parece ser emplearlo en el código de una biblioteca o marco. Como se describe en los documentos, la anotación puede proporcionar un enlace predeterminado fácilmente reemplazado por uno explícito.

Si un tipo está en una bind()declaración (como el primer argumento) y tiene la @ImplementedByanotación, bind()se usa la declaración. La anotación sugiere una implementación predeterminada que se puede anular con un enlace.

De esta manera, como desarrollador de una biblioteca, puedo proporcionar a mis usuarios un enlace listo para usar que se puede personalizar en algún lugar del código del cliente.

¿Es esta la única razón para que exista la anotación? ¿O hay algo que me falta? ¿Puedo obtener algo al usarlo en un código que es solo una aplicación que se ocupa de cierta lógica empresarial y no de una biblioteca / marco para ampliar?

toniedzwiedz
fuente
2
Pregunta relacionada, posiblemente duplicada (aunque su título es más claro): ¿Guice's @ImplementedBy es malo?
Jeff Bowman
No es un duplicado estricto, pero ha habido una discusión interesante sobre esto aquí: stackoverflow.com/questions/6197178/…
Richard Vodden

Respuestas:

8

Creo que el peligro aquí es usar solo la @ImplementedByanotación. Si se usa adecuadamente, junto con las bind()declaraciones de su módulo, etc., está bien.

Tener una implementación predeterminada es excelente para realizar pruebas; no necesariamente quiere tener que definir explícitamente una inyección simulada cada vez que está probando una clase que tiene muchas dependencias, o si tiene una clase de la que dependen muchas cosas (por lo que debe definir una simulación cada vez )

Por ejemplo, podrías tener una clase:

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

Y luego NoOpDataServicees:

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

Nunca usará esto en su código real, obviamente; en su módulo Guice vincularía una implementación que realmente hace algo. Pero todas las pruebas en las clases que se inyectan DataServiceya no necesitan tener un enlace simulado.

tl; dr Estoy de acuerdo con usted en que tener sus interfaces dependen de su implementación puede ser un olor a código; pero también puede eliminar el código repetitivo para facilitar las pruebas. No es una característica difícil de implementar; y aunque existe un pequeño potencial de abuso, en última instancia, las consecuencias no pueden ser tan malas (un servicio se inicia por sorpresa), y no sería demasiado difícil de solucionar, incluso si sucede.

durron597
fuente
3
¿Agregar código de prueba a producción?
Basilevs