Conteneur d'injection de dépendances pour C++ : aperçu et exemples pratiques
\n\nDans le développement moderne en C++, les principes d'Inversion of Control (IoC) et de Dependency Injection (DI) sont de plus en plus utilisés. Ces modèles permettent de créer un code faiblement couplé, testable et facilement extensible. Contrairement aux langages à mémoire gérée (Java, C#), C++ ne dispose pas de réflexion intégrée, donc l'implémentation de conteneurs DI nécessite ici de la métaprogrammation de templates et l'utilisation de normes modernes (C++11/14/17/20).
\n\nDans cet article, nous examinerons trois approches populaires de l'injection de dépendances en C++ : les bibliothèques Boost.DI, Google Fruit et Kangaru, et nous écrirons également notre propre conteneur simple pour comprendre la mécanique.
\n\nQu'est-ce que l'injection de dépendances ?
\n\nL'injection de dépendances est une technique par laquelle un objet reçoit ses dépendances de l'extérieur, plutôt que de les créer lui-même. Les principaux types de DI :
\n- \n
- Constructor Injection — les dépendances sont transmises via le constructeur. \n
- Setter Injection — les dépendances sont définies via des setters. \n
- Interface Injection — les dépendances sont transmises via une interface. \n
Exemple sans DI (couplage fort) :
\nclass Logger {\npublic:\n void log(const std::string& msg) { /* écriture dans un fichier */ }\n};\n\nclass Service {\n Logger logger; // Dépendance forte\npublic:\n void doWork() { logger.log("Work done"); }\n};\n\nExemple avec DI (couplage faible) :
\nclass ILogger {\npublic:\n virtual ~ILogger() = default;\n virtual void log(const std::string& msg) = 0;\n};\n\nclass ConsoleLogger : public ILogger {\npublic:\n void log(const std::string& msg) override { std::cout << msg << std::endl; }\n};\n\nclass Service {\n std::shared_ptr<ILogger> logger;\npublic:\n explicit Service(std::shared_ptr<ILogger> l) : logger(std::move(l)) {}\n void doWork() { logger->log("Work done"); }\n};\n\nAperçu des conteneurs DI pour C++
\n\n1. Boost.DI
\nBoost.DI — l'une des bibliothèques les plus populaires. Elle utilise les templates C++14/17 pour la résolution automatique des dépendances. Elle prend en charge le polymorphisme, les portées (singleton, unique) et la configuration modulaire.
\n\nExemple d'utilisation :
\n#include <boost/di.hpp>\n#include <iostream>\n\nnamespace di = boost::di;\n\nclass IWriter {\npublic:\n virtual ~IWriter() = default;\n virtual void write(const std::string&) = 0;\n};\n\nclass ConsoleWriter : public IWriter {\npublic:\n void write(const std::string& msg) override {\n std::cout << msg << std::endl;\n }\n};\n\nclass App {\n std::shared_ptr<IWriter> writer;\npublic:\n explicit App(std::shared_ptr<IWriter> w) : writer(std::move(w)) {}\n void run() { writer->write("Hello from Boost.DI!"); }\n};\n\nint main() {\n auto injector = di::make_injector(\n di::bind<IWriter>.to<ConsoleWriter>()\n );\n auto app = injector.create<std::unique_ptr<App>>();\n app->run();\n return 0;\n}\n\nAvantages : typage puissant, surcharge d'exécution minimale, prise en charge de C++14/17.
\nInconvénients : messages d'erreur de compilation complexes, augmentation du temps de construction.
\n\n2. Google Fruit
\nGoogle Fruit — un conteneur de Google, fonctionnant avec C++11. Il utilise des macros pour enregistrer les composants et prend en charge l'injection via le constructeur.
\n\nExemple :
\n#include <fruit/fruit.h>\n#include <iostream>\n\nclass IWriter {\npublic:\n virtual void write(const std::string&) = 0;\n};\n\nclass ConsoleWriter : public IWriter {\npubli Aussi dans la bibliothèque
Drogon C++ : guide complet avec exemples pratiques
Travailler avec CSV en C++ : bibliothèque libcsv et outils standard
Travailler avec CSV en PHP : lecture, écriture et traitement des données
Travailler avec XML en JavaScript (Node.js) : bibliothèques et exemples