Dependency Injection in C++: vollständiger Leitfaden mit Beispielen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einführung in Dependency Injection in C++



In der modernen C++-Entwicklung ist Dependency Injection (DI) – die Abhängigkeitsinjektion – eines der Schlüsselprinzipien zur Erstellung von flexiblem und testbarem Code. Dieses Entwurfsmuster ermöglicht es, die Kopplung zwischen Systemkomponenten zu reduzieren, wodurch der Code modularer, wiederverwendbarer und einfacher zu testen wird.



In diesem Artikel werden wir untersuchen, was Dependency Injection in C++ ist, welche Probleme es löst, verschiedene Möglichkeiten seiner praktischen Umsetzung betrachten und Codebeispiele liefern, die Ihnen helfen, diesen Ansatz in Ihren Projekten zu implementieren.



Das Problem der direkten Abhängigkeit



Bevor wir über die Lösung sprechen, betrachten wir ein typisches Problem. Stellen Sie sich vor, wir haben eine Klasse UserService, die Logger zum Schreiben von Logs verwendet:



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

class UserService {private: Logger logger; // Feste Abhängigkeitpublic: void createUser(const std::string& name) { logger.log("Creating user: " + name); // ... Logik zur Benutzererstellung }};


Hier erstellt UserService selbst eine Instanz von Logger. Dies führt zu mehreren Problemen:

  • Schwierigkeit beim Testen: Es ist unmöglich, den Logger während der Unit-Tests durch ein Mock-Objekt zu ersetzen.
  • Starke Kopplung: Eine Änderung des Konstruktors von Logger erfordert Änderungen in allen Klassen, die ihn verwenden.
  • Verletzung des SRP (Single Responsibility Principle): Die Klasse ist nicht nur für ihre eigene Logik verantwortlich, sondern auch für die Erstellung ihrer Abhängigkeiten.


Was ist Dependency Injection?



Dependency Injection ist ein Muster, bei dem ein Objekt seine Abhängigkeiten von außen erhält, anstatt sie selbst zu erstellen. Die Grundidee: "Frage nicht, sondern erhalte".



In C++ gibt es drei Hauptmethoden der Abhängigkeitsinjektion:

  • Constructor Injection – über den Konstruktor.
  • Setter Injection – über Setter-Methoden.
  • Interface Injection – über ein Interface.


1. Constructor Injection (Injektion über den Konstruktor)



Dies ist die gebräuchlichste und bevorzugte Methode. Die Abhängigkeiten werden an den Konstruktor der Klasse übergeben:



#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 { // Logik zum Schreiben in eine Datei std::cout << "[FILE]: " << message << std::endl; }};

class UserService {private: std::unique_ptr<ILogger> logger_; // Abhängigkeit über Interfacepublic: // Constructor Injection explicit UserService(std::unique_ptr<ILogger> logger) : logger_(std::move(logger)) {}

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

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


Vorteile:

  • Die Abhängigkeit ist in der Konstruktorsignatur deutlich sichtbar.
  • Das Objekt befindet sich nach der Erstellung immer in einem gültigen Zustand.
  • Einfach zu testen – man kann

Blogs

Buchempfehlungen