Injection de dépendances (Dependency Injection) en C++ : conteneurs et pratique

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Conteneur d'injection de dépendances pour C++ : aperçu et exemples pratiques

\n\n

Dans 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\n

Dans 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\n

Qu'est-ce que l'injection de dépendances ?

\n\n

L'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
\n\n

Exemple sans DI (couplage fort) :

\n
class 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\n

Exemple avec DI (couplage faible) :

\n
class 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\n

Aperçu des conteneurs DI pour C++

\n\n

1. Boost.DI

\n

Boost.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\n

Exemple 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\n

Avantages : typage puissant, surcharge d'exécution minimale, prise en charge de C++14/17.

\n

Inconvénients : messages d'erreur de compilation complexes, augmentation du temps de construction.

\n\n

2. Google Fruit

\n

Google 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\n

Exemple :

\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                    

Recommendations