Los juegos de estrategia y de rol me ayudaron a entender la programación orientada a objetos y ciertos patrones de diseño. En Warcraft cada unidad (ej: un arquero) es un objeto que interactúa con otras unidades (objetos), el mapa en sí es un objeto que encapsula todos los objetos anteriores.
Una barraca es también un objeto que implementa el patrón Factory porque “produce” otros objetos (soldados). Un héroe podría implementar el patrón “singleton” dado que es único en cada partida.
Así que para aprender fácilmente qué es la inyección de dependencias imaginemos que estamos construyendo el backend de un juego:
Código :
<?php class Bow { // Code here } class Elf extends Unit { protected $bow public function __construct() { $this->bow = new Bow; } public function shoot($target) { return $this->bow->shoot($target); } } class Orc extends Unit { //Code here } $elf = new Elf; $elf->setName('Legolas'); $orc = new Orc; $elf->shoot($orc);
Cada elfo es un objeto que tiene una dependencia en otro objeto (en este caso un arco), además, a medida que el elfo aumente de nivel necesitará de otros arcos más potentes.
¿Con nuestro código actual cómo podemos hacer eso? Respuesta: no podemos. Nuestro heroe está “atado” a usar un sólo tipo de arco y a medida que sus enemigos se vuelvan más fuertes y numerosos no podrá contra ellos y morirá, y será tu culpa.
Inyección de dependencias al rescate
Refactoricemos:
Código :
<?php interface BowInterface { public function shoot($target); } class Bow implements BowInterface { public function shoot($target) { // I don't know how to shoot arrows with PHP yet } } class Elf extends Unit { protected $bow /** * Dependency injection using the class constructor */ public function __construct(BowInterface $bow = null) { if (is_null($bow)) { $this->bow = new Bow; } else { $this->bow = $bow; } } /** * Dependency injection using a setter method */ public function setBow(BowInterface $bow) { $this->bow = $bow; } public function shoot($target) { return $this->bow->shoot($target); } }
Ahora la clase Elf recibe el arco como parámetro a través del constructor de la clase, es decir que cuando creemos un elfo podemos inyectar un arco diferente:
Código :
$elf = new Elf(new LongBow);
También podemos cambiar de arco en cualquier momento usando el método setter, otra forma de inyectar una dependencia:
Código :
$elf->setBow(new LongBow);
Uso de interfaces
Una interfaz nos permite crear implementaciones de forma segura. En nuestro ejemplo siempre que “LongBow” o cualquier arco que creemos “implemente” la interfaz "BowInterface" podrá ser usada por el objeto Elf sin problemas:
Código :
class LongBow implements BowInterface { public function shoot($target) { // A long bow should have more range and be more powerful } }
Conclusión
La inyección de dependencias es el fondo un concepto sencillo que hará tus objetos mucho más flexibles y menos dependientes unos de otros.
En un próximo tutorial veremos este concepto con el framework Laravel
Sígueme en Twitter si estás interesado en más tutoriales o quieres hacerme alguna consulta.
¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.
Por gmlo_89 el 15 de Enero de 2014
public function __construct(BowInterface $bow = null)
{
if (is_null($bow))
{
$this->bow = new Bow;
}
$this->bow = $bow;
}
No te falto un else después de las llaves? por que si $bow es null entonces siempre va tomar el valor de null no?
Saludos.
Por Duilio el 15 de Enero de 2014
gmlo_89 :
public function __construct(BowInterface $bow = null)
{
if (is_null($bow))
{
$this->bow = new Bow;
}
$this->bow = $bow;
}
No te falto un else después de las llaves? por que si $bow es null entonces siempre va tomar el valor de null no?
Saludos.
Tienes razón, good catch. Pediré que lo arreglen.
Colocar el else o:
$bow = new Bow;
Que era mi idea original.
Bueno la idea es demostrar que con inyección de dependencias se pueden usar valores por defecto tambien.
Gracias! Saludos
Por Mariux el 16 de Enero de 2014
Duilio :
gmlo_89 :
public function __construct(BowInterface $bow = null)
{
if (is_null($bow))
{
$this->bow = new Bow;
}
$this->bow = $bow;
}
No te falto un else después de las llaves? por que si $bow es null entonces siempre va tomar el valor de null no?
Saludos.
Tienes razón, good catch. Pediré que lo arreglen.
Colocar el else o:
$bow = new Bow;
Que era mi idea original.
Bueno la idea es demostrar que con inyección de dependencias se pueden usar valores por defecto tambien.
Gracias! Saludos
porfa, enviame el código arreglado por DM así lo arreglo y no sale con errores. gracias!
Por Frank el 27 de Septiembre de 2014
isnull($bow) ? $this->bow = new Bow : $this->bow = $bow;
Espero sea de ayuda.
Por Masakre el 23 de Marzo de 2015
$this->bow = isnull($bow) ? new Bow : $bow;