A minimalistic C++17 dependency injection framework.
A key characteristic of software is that it needs to be changed over time as requirements evolve. By de-coupling different parts of a program from each other, we can reduce the effort that comes with such changes. The resuling architecture often looks like this:
- The program is divided into components.
- Component interface and implementation are separate.
- Dependencies between components are against interfaces, not implementations.
In this context, dependency injection solves the problem of constructing components and assembling them in a flexible and convenient way.
Add di.h and di.cpp to your project and
#include "di.h"class Greeter
{
virtual void greet() = 0;
};class Printer
{
virtual void print(std::string_view text) = 0;
};class GreeterImpl : public Greeter
{
void greet() override
{
printer->print("Hello!");
}
di::ServiceRef<Printer> printer;
};class ConsolePrinterImpl : public Printer
{
void print(std::string_view text) override
{
std::cout << text << std::endl;
}
};class FilePrinterImpl : public Printer
{
FilePrinterImpl(std::string_view fn) { f.open(std::string(fn)); }
~FilePrinterImpl() { f.close(); }
void print(std::string_view text) override
{
f << text << std::endl;
}
std::ofstream f;
};auto consoleApp = di::Bindings{}
.service<Greeter, GreeterImpl>()
.service<Printer, ConsolePrinterImpl>();auto loggingApp = di::Bindings{}
.service<Greeter, GreeterImpl>()
.service<Printer, FilePrinterImpl>("log.txt");{
auto scope = di::Scope{consoleApp};
di::ServiceRef<Greeter> greeter;
greeter->greet(); // Greets to console
}{
auto scope = di::Scope{loggingApp};
di::ServiceRef<Greeter> greeter;
greeter->greet(); // Greets to log.txt
}This framework is work-in-progress and should not be used in production yet.