El problema del "conocimiento de implementación"

Como vimos, nuestro Service tiene un serio problema con el Repository: conoce su implementación. ¿Cómo hacer entonces para usar el Repository sin conocer la implementación?

Evidentemente, deberemos evitar hacer un "new ProvinciaRepositoryDummyImpl()" o, para el caso, un "new" de cualquier Repository que se use. Como vimos, el realizar un "new" nos acopla con una implementación particular de un Repository.

La solución: inyección de dependencia

Ya que el problema es realizar el "new", es evidente que nuestro Service no deberá más instanciar él mismo al Repository. Es decir, delegaremos la instanciación de este Repositorya un tercero.

Aquí aplicaremos un patrón que será fundamental en el diseño de nuestras aplicaciones JEE: se trata de la Inyección de Dependencia (Dependency Inyection - DI). Este patrón establece que un objeto no es el responsable de setear sus dependencias, sino que las mismas deben ser seteadas por un tercero.

Así, lo que haremos en la implementación del Service será:

  1. ubicar al Repository como atributo privado de nuestro Service (en el Diagrama de Clases)
  2. crearle los getters/setters correspondientes (en el Diagrama de Clases)
  3. usar directamente este atributo privado en nuestro método principal (en el Diagrama de Secuencia)
  4. actualizar el código para reflejar estos cambios

Ahora bien, cuando ejecutes los tests, los mismos fallarán por un simpático NullPointerException seguramente... y es que, ¿quién está seteando a nuestro Repository? Será entonces nuestro test quien deba crear una instancia del Repository, setearsela al Service, y recién entonces ejecutar el test. A modificar el test entonces!

Con los test retocados, los mismos deberían volver a su estado "verde feliz".

Conclusión

Aprendimos entonces la idea del patrón de inyección de depencia. Con esto, solucionamos el problema en nuestro Service: ahora ya no conoce la implementación del Repository. De hecho, no tiene ningún medio para obtenerlo, tan sólo espera que esté correctamente seteado.

Obviamente, esto nos genera otra pregunta: si el Service no setea sus dependencias, ¿quién lo hará en la ejecución real? Evidentemente alguien deberá ser el responsable de conocer las implementaciones y setear las dependencias de los objetos. Este tema lo resolveremos más adelante; por ahora basta saber que los objetos "tendrán las dependencias seteadas", sin importar cómo.

Realizaremos el primer refactor de código, cambiando la implementación del Service, y resolviendo uno de los problemas.