Tutorial de Spring 2.5.6 en español – Comprender la inyeccion de dependencias

La inyeccion de dependencias en una tecnica que ha permitido disminuir el acoplamiento entre clases.

El problema del acoplamiento es que es rigido y para hacer un cambio en una clase que depende de otra, se debe dedicar mas esfuerzo.

Por ejemplo considerar la siguiente clase Knight : Caballero.

package com.springinaction.chapter01.knight;

public class KnightOfTheRoundTable {
	private String name;
	private HolyGrailQuest quest;

	public KnightOfTheRoundTable(String name) {
		this.name = name;
		quest = new HolyGrailQuest();
	}

	public HolyGrail embarkOnQuest() throws GrailNotFoundException {
		return quest.embark();
	}
}

Esta clase tiene dos atributos :

private String name;
private HolyGrailQuest quest;

Una instancia de esta clase  (Un caballero de la mesa redonda) esta hecha para que el caballero se embarque en una cruzada para encontrar el Grial.

package com.springinaction.chapter01.knight;

public class HolyGrailQuest {
	public HolyGrailQuest() {}

		public HolyGrail embark() throws GrailNotFoundException {
			HolyGrail grail = null;
			// Look for grail
			//…
			return grail;
		}
	}

Si se desea comprobar la clase , se debe hacer una prueba unitaria, que ayudara a comprobar algunas condiciones que pueden generar error.

El codigo de la prueba es :

package com.springinaction.chapter01.knight;
import junit.framework.TestCase;
public class KnightOfTheRoundTableTest extends TestCase {

	public void testEmbarkOnQuest() throws GrailNotFoundException {
		KnightOfTheRoundTable knight = new KnightOfTheRoundTable(“Bedivere”);
		HolyGrail grail = knight.embarkOnQuest();
		assertNotNull(grail);
		assertTrue(grail.isHoly());
	}
}

Despues de crear al “caballero” , se procede a hacer las pruebas unitarias

La sentencia, prueba si el grail no es un objeto nulo.

assertNotNull(grail);

La sentencia, prueba si el metodo devuelve true.
assertTrue(grail.isHoly());

Se aprecia que la instancia de KnightOfTheRoundTable tambien aplica la prueba unitaria a la clase HolyGrailQuest.

Es en este punto donde se evidencia el acoplamiento entre KnightOfTheRoundTable y HolyGrailQuest.

Debido a la forma del codigo , a la clase KnightOfTheRoundTable, no se le puede aplicar una prueba unitaria, porque en su constructor crea un objeto del cual depende.

Una alternativa para “desacoplar” KnightOfTheRoundTable de otra clase sin modificar la forma de su codigo (principalmente el constructor ), es usar interfaces.

Los primeros cambios que seran seran aplicados son crear las sgtes interfaces:

1. Quest : para desacoplar HolyGrailQuest.
2. Knight : para desacoplar KnightOfTheRoundTable.

Ademas se deberá modificar las sgtes clases :
3. HolyGrailQuest para que extienda de Quest.
4. KnightOfTheRoundTable para que extienda de Knight .

package com.springinaction.chapter01.knight;
	public interface Quest {
		abstract Object embark() throws QuestFailedException;
}

En esta interfaz se declara el metodo embark() que retorna un Object y puede lanzar una QuestFailedException.

package com.springinaction.chapter01.knight;
	public class HolyGrailQuest implements Quest {
		public HolyGrailQuest() {}

		public Object embark() throws QuestFailedException {
			// Do whatever it means to embark on a quest
			return new HolyGrail();
		}
}

En esta clase se implementa Quest (linea 2 ) y se implementa su metodo embark().

public interface Knight {
	Object embarkOnQuest() throws QuestFailedException;
}
package com.springinaction.chapter01.knight;
	public class KnightOfTheRoundTable implements Knight {
		private String name;
		private Quest quest;

		public KnightOfTheRoundTable(String name) {
			this.name = name;
			quest = new HolyGrailQuest();
		}
		public Object embarkOnQuest() throws QuestFailedException {
			return quest.embark();
		}
}

Con las interfaces hechas e implementadas, se procede otra vez a hacer una prueba unitaria a la clase KnightOfTheRoundTable.
El problema aun persiste, porque de todas formas en el constructor de esta clase se evidencia la dependencia con la interfaz Quest , en este caso con la creacion de una instancia de la clase HolyGrailQuest (linea 8).
El caballero esta enfrascado solamente en rescates de bellas damas en castillos.

Esta dependencia que esta demasiado unida al ciclo de vida de las instancias de KnightOfTheRoundTable (en la creacion) , se puede disminuir quitando la creacion de la instancia en el momento en que se instancia al caballero (linea 8).
El sgte codigo muestra como se hacen estos cambios en la clase para lograr el desacoplamiento entre estas dos clases KnightOfTheRoundTable y Quest :

package com.springinaction.chapter01.knight;
	public class KnightOfTheRoundTable implements Knight {
		private String name;
		private Quest quest;

		public KnightOfTheRoundTable(String name) {
			this.name = name;
		}

		public Object embarkOnQuest() throws QuestFailedException {
			return quest.embark();
		}

		public void setQuest(Quest quest) {
			this.quest = quest;
		}
}

en la linea 8, se aplico un cambio que consistio en eliminar la creacion del objeto Quest.
En la linea 14 se declaro un metodo set para el objeto Quest.
Estos dos cambios producen que la dependencia entre estas dos clases disminuya.
Ahora el caballero podra realizar las cruzadas que quiera, sin ser todas necesariamente Rescates de bellas damas en castillos.

Inicializacion y seteo de clases dependientes :

Una vez que ya tenemos la clase caballero que tiene como trabajo embarcarse en cruzadas, se necesita asignar el tipo de cruzada dependiendo del tipo cada vez que el caballero se embarca en una.

esto podria hacerse en codigo, llamando al metodo setQuest() , pero el caballero podria quedarse sin cruzada o esperando indefinidamente si es que a alguien se le olvida decirle a que cruzada ir.

En Spring esto lo lleva a cabo el contenedor y en la etapa de creacion del caballero.

Para eso se usa un archivo de configuracion con unas sentencias que seran leidas por el contenedor Spring.

En el contenido del archivo hay declaraciones acerca de los objetos a crear y asociar en un primer momento.

El lenguaje es declarativo, y conceptualmente quiere decir que esta orientado obtener un resultado. Por ejemplo un lenguaje declarativo es SQL.
Los lenguajes como C++,Java, C# son lenguajes procedurales, es decir con ellos se puede indicar la como se puede obtener un resultado.

Para graficar la idea ubiquemosmo en una situacion real. Iremos a mostrar la diferencia en como se obtiene un resultado tanto en un lenguaje declarativo como en un lenguaje procedural. La situacion es ir a consumir un cafe y una tostada en una cafeteria. En el caso de un lenguaje declarativo usted puede ir a una cafeteria y en el lenguaje declarativo decir : “quiero un cafe y una tostada con mantequilla” y obtiene su pedido.
En el lenguaje procedural usted va a la cafeteria y le dice al empleado quiero un cafe :
-coja una taza.
-añada agua caliente
-añada 2 cucharadas de cafe
– …
– Ponga la tostada en el tostador
– …
– agregue mantequilla
-traiga el cafe y la tostada hasta mi mesa.

Un lenguaje declarativo es mas cercano a la forma en que nosotros nos comunicamos y es mucho mas facil de entender.
Como podra analizar alguien debe hacer el trabajo oculto en el caso declarativo, en SQL es el motor de Base de datos y en el caso de Spring es el contenedor mismo.

Volviendo al archivo de declaracion de objetos,se pondra el sgte codigo :

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

	<bean id="quest" class="com.springinaction.chapter01.knight.HolyGrailQuest"/>
	<bean id="knight" class="com.springinaction.chapter01.knight.KnightOfTheRoundTable">
	<constructor-arg value="Bedivere"/ >
	<property name="quest" ref="quest" />
	</bean>

</beans>

En el codigo se declara un bean con id quest y otro con id knight, en esas lineas se esta indicando de forma declarativa al contenedor que necesitamos un bean de tipo HolyGrailquest con nombre quest y otro de tipo KnightOfTheRoundTable y con nombre knight.
Ademas mediante constructor-arg le pasamos el value “Bedivere” al constructor de su Clase.
Y con property name asignamos a la propiedad de KnightOfTheRoundTable con nombre “quest” una referencia al bean “quest”.

El trabajo oculto lo hace el contenedor de Spring y poduce un código equivalente a lo sgte.


Quest quest = (Quest) new com.springinaction.chapter01.knight.HolyGrailQuest();
Knight knight = (Knight) new com.springinaction.chapter01.knight.KnightOfTheRoundTable("Bedivere");
knight.quest=quest;

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s