Comunidad de diseño web y desarrollo en internet

POO: Inyección de dependencias

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
    }
}


En una interfaz sólo definimos los “headers” de cada método que sea necesario implementar, ejemplo: public function shoot($target) las clases que implementen una interfaz deben definir cada uno de esos método con su correspondiente implementación de código.


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. :D

¿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.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate