Inyección de Dependencias en C++: guía completa con ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción a Dependency Injection en C++



En el desarrollo moderno con C++, uno de los principios clave para crear código flexible y comprobable es Dependency Injection (DI) — inyección de dependencias. Este patrón de diseño permite reducir el acoplamiento entre los componentes del sistema, haciendo que el código sea más modular, reutilizable y fácil de probar.



En este artículo, analizaremos qué es Dependency Injection en C++, qué problemas resuelve, exploraremos diferentes formas de implementarlo en la práctica y proporcionaremos ejemplos de código que le ayudarán a incorporar este enfoque en sus proyectos.



El problema de la dependencia directa



Antes de hablar de la solución, veamos un problema típico. Imagine que tenemos una clase UserService que utiliza Logger para registrar logs:



class Logger {public:    void log(const std::string& message) {        std::cout << "[LOG]: " << message << std::endl;    }};

class UserService {private: Logger logger; // Dependencia rígidapublic: void createUser(const std::string& name) { logger.log("Creating user: " + name); // ... lógica de creación de usuario }};


Aquí, UserService crea su propia instancia de Logger. Esto genera varios problemas:

  • Dificultad para realizar pruebas: es imposible reemplazar el logger por un objeto mock durante las pruebas unitarias.
  • Alto acoplamiento: cambiar el constructor de Logger requerirá modificar todas las clases que lo utilizan.
  • Violación del SRP (Single Responsibility Principle): la clase no solo se encarga de su propia lógica, sino también de crear sus dependencias.


¿Qué es Dependency Injection?



Dependency Injection es un patrón en el cual un objeto recibe sus dependencias desde el exterior, en lugar de crearlas por sí mismo. La idea principal es: "no preguntes, recibe".



En C++, existen tres formas principales de inyectar dependencias:

  • Constructor Injection — a través del constructor.
  • Setter Injection — a través de métodos setter.
  • Interface Injection — a través de una interfaz.


1. Constructor Injection (Inyección a través del constructor)



Esta es la forma más común y preferida. Las dependencias se pasan al constructor de la clase:



#include <memory>#include <iostream>

class ILogger {public: virtual ~ILogger() = default; virtual void log(const std::string& message) = 0;};

class ConsoleLogger : public ILogger {public: void log(const std::string& message) override { std::cout << "[CONSOLE]: " << message << std::endl; }};

class FileLogger : public ILogger {public: void log(const std::string& message) override { // Lógica de escritura en archivo std::cout << "[FILE]: " << message << std::endl; }};

class UserService {private: std::unique_ptr<ILogger> logger_; // Dependencia a través de interfazpublic: // Constructor Injection explicit UserService(std::unique_ptr<ILogger> logger) : logger_(std::move(logger)) {}

void createUser(const std::string& name) { logger_->log("Creating user: " + name); // ... lógica }};

int main() { auto consoleLogger = std::make_unique<ConsoleLogger>(); UserService service(std::move(consoleLogger)); service.createUser("Alice"); return 0;}


Ventajas:

  • La dependencia es explícitamente visible en la firma del constructor.
  • El objeto siempre se encuentra en un estado válido después de su creación.
  • Fácil de probar: se puede sustituir

Blogs

Book Recommendations