Contenedor de Dependency Injection para C++: descripción general y ejemplos prácticos
En el desarrollo moderno con C++, los principios de Inversion of Control (IoC) y Dependency Injection (DI) se aplican cada vez más. Estos patrones permiten crear código débilmente acoplado, comprobable y fácilmente extensible. A diferencia de los lenguajes con memoria administrada (Java, C#), C++ no tiene reflexión incorporada, por lo que la implementación de contenedores DI aquí requiere metaprogramación de plantillas y el uso de estándares modernos (C++11/14/17/20).
En este artículo, veremos tres enfoques populares para la inyección de dependencias en C++: las bibliotecas Boost.DI, Google Fruit y Kangaru, y también escribiremos nuestro propio contenedor simple para comprender la mecánica.
¿Qué es la Inyección de Dependencias?
La Inyección de Dependencias es una técnica mediante la cual un objeto recibe sus dependencias desde el exterior, en lugar de crearlas él mismo. Los principales tipos de DI son:
- Constructor Injection — las dependencias se pasan a través del constructor.
- Setter Injection — las dependencias se establecen a través de setters.
- Interface Injection — las dependencias se pasan a través de una interfaz.
Ejemplo sin DI (acoplamiento fuerte):
class Logger {public: void log(const std::string& msg) { /* escribir en archivo */ }};
class Service { Logger logger; // Dependencia fuertepublic: void doWork() { logger.log("Work done"); }};Ejemplo con DI (acoplamiento débil):
class ILogger {public: virtual ~ILogger() = default; virtual void log(const std::string& msg) = 0;};
class ConsoleLogger : public ILogger {public: void log(const std::string& msg) override { std::cout << msg << std::endl; }};
class Service { std::shared_ptr<ILogger> logger;public: explicit Service(std::shared_ptr<ILogger> l) : logger(std::move(l)) {} void doWork() { logger->log("Work done"); }};Descripción general de los contenedores DI para C++
1. Boost.DI
Boost.DI es una de las bibliotecas más populares. Utiliza plantillas de C++14/17 para la resolución automática de dependencias. Admite polimorfismo, ámbitos (singleton, unique) y configuración modular.
Ejemplo de uso:
#include <boost/di.hpp>#include <iostream>
namespace di = boost::di;
class IWriter {public: virtual ~IWriter() = default; virtual void write(const std::string&) = 0;};
class ConsoleWriter : public IWriter {public: void write(const std::string& msg) override { std::cout << msg << std::endl; }};
class App { std::shared_ptr<IWriter> writer;public: explicit App(std::shared_ptr<IWriter> w) : writer(std::move(w)) {} void run() { writer->write("Hello from Boost.DI!"); }};
int main() { auto injector = di::make_injector( di::bind<IWriter>.to<ConsoleWriter>() ); auto app = injector.create<std::unique_ptr<App>>(); app->run(); return 0;}Ventajas: tipado fuerte, sobrecarga mínima en tiempo de ejecución, soporte para C++14/17.
Desventajas: mensajes de error de compilación complejos, aumento del tiempo de compilación.
2. Google Fruit
Google Fruit es un contenedor de Google que funciona con C++11. Utiliza macros para registrar componentes y admite inyección a través del constructor.
Ejemplo:
#include <fruit/fruit.h>#include <iostream>
class IWriter {public: virtual void write(const std::string&) = 0;};
class ConsoleWriter : public IWriter {publi También en la biblioteca
GraphQL para Swift: Apollo iOS — cliente para iOS y macOS
Contenedor de Inyección de Dependencias Swift: Swinject para iOS/macOS
Envío de SMS en Java: resumen de bibliotecas API (Twilio, Nexmo, pasarelas SMS)
Trabajo con Apache Kafka en Swift (iOS/macOS): bibliotecas y ejemplos
OneOf para C# (.NET): guía completa con ejemplos prácticos