En el post de hoy voy a dejar unos apuntes que me parecen muy fáciles de entender con respecto a la inyección de dependencias en Java. Estas inyecciones son un patrón de diseño que deriba en un patrón más genérico llamado Inversión de Control. La inyección de dependencias hace uso de la modularidad y la reutilización posible en este lenguaje, para utilizarlas siempre habrá que tener en cuenta si la aplicaciones que desarrollamos va a tener disponible una mayor funcionalidad
Los código que voy a utilizar para ejemplificar este concepto no es propio, lo encontré buscando un poco por google. En el se verá la representación de una puerta con cerradura de llave y una puerta con cerradura de código. Esta sería la representación sin el uso de la inyección de dependencias:
Ejemplo de inyección de dependecias en Java
Start.java
public class Start {
public static void main(String[] args) {
//Usamos una puerta con cerradura de llave
ObjetoPuertaLlave puertaLlave = new ObjetoPuertaLlave();
puertaLlave.abrir();
//Usamos una puerta con cerradura de código
ObjetoPuertaCodigo puertaCodigo = new ObjetoPuertaCodigo();
puertaCodigo.abrir();
}
}
Esto es lo que se ha hecho toda la vida, se crea un nuevo objeto «puerta» que tenga una «cerradura» de tipo «llave» por un lado y otro que tenga una cerradura de tipo «código».
ObjetoPuertaLlave.java:
public class ObjetoPuertaLlave {
private ObjetoCerraduraLlave cerradura;
public ObjetoPuertaLlave(){
cerradura = new ObjetoCerraduraLlave();
}
public void abrir(){
cerradura.accionar();
}
}
ObjetoCerraduraLlave.java:
public class ObjetoCerraduraLlave{
public void accionar() {
System.out.println("Cerradura con Llave");
}
}
ObjetoPuertaCodigo.java:
public class ObjetoPuertaCodigo {
private ObjetoCerraduraCodigo cerradura;
public ObjetoPuertaCodigo(){
cerradura = new ObjetoCerraduraCodigo();
}
public void abrir(){
cerradura.accionar();
}
}
ObjetoCerraduraCodigo.java:
public class ObjetoCerraduraCodigo{
public void accionar() {
System.out.println("Cerradura con Código");
}
}
La salida por consola de la ejecución es la siguiente vendría siendo algo como esto:
Cerradura con Llave
Cerradura con Código
Obviamente esta no es la mejor manera de implementar esta representación. Ahora veremos como usar inyección de dependencias para hacer esto mismo pero más reutilizable. En este ejemplo sólo tendremos una clase puerta:
ObjetoPuerta.java:
public class ObjetoPuerta {
private CerraduraInterface cerradura;
public ObjetoPuerta(CerraduraInterface cerraduraGeneric){
cerradura = cerraduraGeneric;
}
public void usar(){
cerradura.accionar();
}
}
Esta clase puerta es más genérica que la anterior y consta de un atributo que es una interface. Esto es a groso modo la inyección de dependencias, en la que en lugar de invocar instancias nuevas de objetos desde la propia clase, se invocan desde fuera de esta. Estas instancias serán pasadas como parámetros. De esta manera, este ObjetoPuerta nos servirá para representar cualquier puerta que tenga una cerradura siempre y cuando ese objeto cerradura implemente la interface que contiene ObjetoPuerta como atributo.
CerraduraInterface.java:
public interface CerraduraInterface {
void accionar();
}
ObjetoCerraduraLlave.java:
public class ObjetoCerraduraLlave implements CerraduraInterface{
@Override
public void accionar() {
System.out.println("Cerradura con Llave");
}
}
ObjetoCerraduraCodigo.java:
public class ObjetoCerraduraCodigo implements CerraduraInterface{
@Override
public void accionar() {
System.out.println("Cerradura con Código");
}
}
Start.java:
public class Start {
public static void main(String[] args) {
ObjetoCerraduraLlave llave = new ObjetoCerraduraLlave();
ObjetoPuerta puerta = new ObjetoPuerta(llave);
puerta.usar();
ObjetoCerraduraCodigo codigo = new ObjetoCerraduraCodigo();
puerta = new ObjetoPuerta(codigo);
puerta.usar();
}
}
La salida de la ejecución es la siguiente:
Cerradura con Llave
Cerradura con Código
Como se puede ver, la salida es la misma en ambos casos. La diferencia es que si quisiéramos añadir una puerta con cerradura de tipo “Reconocimiento_dactilar“, en el primer caso habría que crear un nuevo tipo de puerta que tuviera como atributo un objeto de tipo CerraduraDactilar y ya tendríamos tres objetos distintos cuya única diferencia es el tipo de un atributo. Vamos, que esta no es la mejor manera de optimizar un poco el código.
En el segundo caso, usando inyección de dependencias, bastaría con crear el objeto CerraduraDactilar y pasarla como parámetro al constructor de ObjetoPuerta. Tendríamos un solo ObjetoPuerta y solamente añadiríamos la nueva implementación de la cerradura, ahorrándonos una cuantas líneas de código.
Uno de los problemas que plantea el uso de interfaces viene a la hora de depurar visualmente el código ya que no vemos de que tipo es el objeto que pasamos pues solo vemos su representación como interface. Esto puede ser un problema, pero para eso se inventaron los Debug del IDE de turno.
Alguna gente a estas alturas podría pensar que podríamos haber creado un ObjetoPuerta genérico del que heredasen todos los demás objetosPuerta, con sus atributos cerradura concretos, pero no esto no resolvería el problema de tener objetos iguales cuyas únicas diferencias son un atributo. Entonces como que descartaré esa opción.
Alguien puede preguntarse la utilidad real de este patrón teniendo en cuenta que podríamos tener un ObjetoPuerta con dos o más atributos, o un ObjetoCerradura que tuviera algún atributo, pero volvería a presentarse el problema inicial, ¿creo dos objetos de tipo CerraduraConAtributo y CerraduraSinAtributo o vuelvo a usar inyección de dependecias?.
Pero aún usando la inyección de dependencias tendremos que instanciar los dos tipos de cerradura y pasar como parámetro al ObjetoPuerta la que nos convenga en el momento, tal y como hemos hecho con ObjetoCerraduraCodigo y ObjetoCerraduraLlave.
Para solventar todo esto existe la inversión de control donde mediante la inyección de dependencias y la reflexión se irán creando las instancias de clases que necesitemos según el momento y necesidad trasladando todo el control fuera de la clase principal.
2 Comentarios
Muuuuuuuuuchas Gracias! Ha sido la primer entrada de muchas muchas vistas, incluidos videos, pdf’s y demás donde hay un ejemplo concreto, corto, bien explicado y con un ejemplo REALMENTE implementado dónde se puede ver la aplicabilidad y ejecución del concepto, Muchas Gracias nuevamente!
Me alegro que te sea útil, y gracias a ti por la visita y el comentario. Salu2.