Recientemente leí sobre la @ImplementedBy
anotació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 @ImplementedBy
anotació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
@ImplementedBy
cuidado; 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 @ImplementedBy
valga 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@ImplementedBy
anotació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?
fuente
Respuestas:
Creo que el peligro aquí es usar solo la
@ImplementedBy
anotación. Si se usa adecuadamente, junto con lasbind()
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:
Y luego
NoOpDataService
es: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
DataService
ya 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.
fuente