22 de agosto de 2025
solid-design-principle-1

Partiré señalando que el 90% de lo que expondré tiene que ver con el siguiente razonamiento:

“Programa contra abstracciones”

Es una frase simple que veremos, se repite una y otra vez.

Si estás aquí es que tienes una idea sobre lo que es SOLID, y si no, puedes revisar conceptualmente aquí.

Partiré con el principio que considero en lo personal, es el más interesante de todos:

“D: Dependency inversion principle” (Principio de inversión de dependencias).

La idea tras este principio es no depender directamente de una dependencia concreta, si no modelarla y permitir al implementador decidir qué se va a implementar, después.

Supongamos el siguiente escenario:

  • Tenemos una clase de negocio (MyBusiness) que procesa una acción y esperamos que genere un log en alguna parte.
  • Esa alguna parte “puede” ser una bd, en cinta, un archivo plano u otra cosa. La verdad, no nos interesa decidir ahora concretamente cómo se va a registrar, solo nos interesa saber que se va a guardar.

Ahora, ¿cómo puedo diseñar la solución para que el objeto de negocio le de igual que usar?.

Esto se logra utilizando interfaces.

Una interfaz no es más que un contrato que debe cumplir quien lo implemente, por lo que lo lógico es que nuestra clase dependa de un contrato y no de algo concreto. (generamos una abstracción del proceso diciendo qué y no cómo se va a implementar, es decir, programamos contra abstracciones)

Volvamos a nuestra estructura de MyBusiness que debe registrar un evento.

Diagrama del registro de log de mybusiness

MyBusiness, posee una dependencia llamada log, la cual es inyectada modelando su implementación no importándole cómo ésta sea implementada.

<?php
namespace SOLID\DIP;
use SOLID\DIP\ILog;

class MyBusiness {

    private ILog $logging;

    public function __construct(ILog $logging)
    {
        $this->logging = $logging;
    }

    public function setID($id)
    {
        $this->id = $id;
        $this->logging->info("Initialized ".$this->id);
    }

    public function process()
    {
        $this->logging->info("This is an example");
    }
}

Ahora veamos la definición de interfaz (posee un contrato básico que señala la criticidad del evento a informar)

<?php
namespace SOLID\DIP;

interface ILog {
    
    public function debug($event);
    
    public function info($event);
    
    public function alert($event);
    
    public function critical($event);
}
<?php
namespace SOLID\DIP;

class File implements ILog {

    public function debug($event) {
        error_log($event."\n");
    }

    public function info($event) {
        error_log($event."\n");
    }

    public function alert($event) {
        error_log($event."\n");
    }

    public function critical($event) {
        error_log($event."\n", 3, "contact@mail.generic.test");
    }
}

Por último, nuestro main va a construir la aplicación y pasar el “logger” via inyección de dependencias.

<?php

include __DIR__."MyBusiness.php";
include __DIR__."Repository.php";
include __DIR__."File.php";

$repo = new SOLID\DIP\File();
$ent = new SOLID\DIP\MyBusiness($repo);
$ent->setId(1);
$ent->process();

Nuestra clase MyBusiness no tiene idea cómo se va a implementar lo que le estoy pasando, pero si sabe que contractualmente debe logear cierto nivel de criticidad.

Es decir “programamos contra una abstracción”.

Si quisiéramos implementar un nuevo tipo de log, esta clase debe implementar los métodos declarados en la interface y ser inyectada a la clase MyBusiness.

Si manejo muchas fuentes que implementan un comportamiento, ¿cómo hago mi aplicación configurable?. En este caso se debería crear una Factoría que cree objetos con dependencia similar. Pero, en otro momento hablaré de eso.

Espero que mi post les pueda ayudar a entender un poco mejor estos “principios” que triviales de entender no son.

Por último, nuestro main va a construir la aplicación y pasar el “logger” via inyección de dependencias.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.