Principio de inversi贸n de dependencias
El Principio de Inyecci贸n de Dependencias es una t茅cnica esencial para crear aplicaciones modulares y f谩ciles de probar. Este principio se basa en la idea de que las clases de alto nivel no deben estar r铆gidamente vinculadas a sus dependencias de bajo nivel; en su lugar, ambas deben depender de abstracciones. En la pr谩ctica, esto significa que las clases no deben crear o buscar sus propias dependencias, sino que deben serles proporcionadas, generalmente a trav茅s de interfaces. Dicho de otra manera, las dependencias que se inyectan en las clases deben ser meros contratos (interfaces), y no implementaciones concretas (clases con m茅todos desarrollados).
Ejemplo sencillo
Consideremos, por ejemplo, una interfaz ProductRepository en una aplicaci贸n de comercio electr贸nico. Esta interfaz define los m茅todos esenciales para trabajar con productos, como obtenerlos, agregarlos y eliminarlos. Luego, tenemos dos implementaciones concretas de esta interfaz: SQLProductRepository, que interact煤a con una base de datos SQL, y InMemoryProductRepository, que utiliza una estructura de datos en memoria para pruebas o entornos de desarrollo.
/** Example whitout DIP principle*/final readonly class SQLProductRepository implements ProductRepository{ // Implementaci贸n utilizando base de datos SQL}
final readonly class InMemoryProductRepository implements ProductRepository{ // Implementaci贸n en memoria para pruebas o desarrollo}
final readonly class ProductManager{ public function __construct(private SQLProductRepository $repository) { }
public function processProduct($id) { $product = $this->repository->getProductById($id); // L贸gica para procesar el producto... }}En este ejemplo, ProductManager crea directamente una instancia de SQLProductRepository. Esto significa que est谩 fuertemente acoplado a una implementaci贸n espec铆fica del repositorio. Si decidimos cambiar la fuente de datos a InMemoryProductRepository para pruebas o desarrollo, tendr铆amos que modificar el c贸digo de ProductManager, y lo mismo aplicar铆a si aparecieran nuevas implementaciones de ProductRepository.
/** Example with DIP principle*/interface ProductRepository{ public function getProductById($id); public function addProduct($product); // Otros m茅todos relevantes...}
final readonly class SQLProductRepository implements ProductRepository{ // Implementaci贸n utilizando base de datos SQL}
final readonly class InMemoryProductRepository implements ProductRepository{ // Implementaci贸n en memoria para pruebas o desarrollo}
final readonly class ProductManager{ public function __construct(private ProductRepository $repository) { }
public function processProduct($id) { $product = $this->repository->getProductById($id); // L贸gica para procesar el producto... }}En este caso, ProductManager puede funcionar tanto con un SQLProductRepository como con un InMemoryProductRepository, lo que aumenta enormemente su flexibilidad y facilita la realizaci贸n de pruebas unitarias. Al inyectar la dependencia, ProductManager est谩 acoplado solo a la interfaz ProductRepository, no a una implementaci贸n espec铆fica, permitiendo as铆 una mayor modularidad y facilitando el mantenimiento y la extensi贸n del c贸digo.
Para finalizar
El principio de inversi贸n de dependencia, con el cual desacoplaremos los m贸dulos de nuestros sistemas.