The quest for a c++ Dependency Injection Container library. Part 2, some Sauce

Contents

Introduction

In Part 1 I have started with a list of C++ dependency injection libraries, and sketched an example problem, solved and tested with the help of Wallaroo. For the second part, Hypodermic should have been in focus, but unfortunately, no version compiled out of the box on MacOS with Clang [1. To do in 2014]. Hence, the article is about sauce, an inspiration from google-guice.

Dependency Injection using sauce

A little repetition, the example problem contains of 3 interfaces with a linear dependency graph of the implementations. Not to repeat the implementations, and not change the structure of the existing code, simple factories for the default implementations have been exposed, but not the concrete types in the headers, i.e. for the default renderer implementation:

std::shared_ptr< IRender > NewKeyRenderer(std::shared_ptr< IGetKeyValue > model) {
	return std::make_shared<KeyRenderer>(model);
};

Implementations

Simplified, the sauce solution looks as follows. Unlike in Wallaroo, in sauce, the implementations do not need to derive from a common “dependency” class. Any type can be bound to any derived class. The implementation of a renderer for the sauce example just adds a delegation to the original implementation [2. Efficiency and overhead are not considered in the first place.]:

class SauceKeyRenderer : public IRender {
public:
	SauceKeyRenderer(std::shared_ptr< IGetKeyValue > m) :
	pimpl ( NewKeyRenderer(m) )
	{ }

public:
	virtual std::string Render() {
		//...
		return pimpl->Render();
	}

private:
 	std::shared_ptr< IRender > pimpl;
};

Modules

Modules are containers of bindings of interfaces to their implementations. The easiest way to define a module is to provide a function with the signature void (* module)(sauce::Binder &).

Here’s the self-explaining module:

void render_module(sauce::Binder& b) {
	b.bind<IRender>().to<SauceKeyRenderer(IGetKeyValue&)>();
}

Once again, obviously, the type doesn’t have to leak outside the module due to inversion of control.

Note that the IGetKeyValue dependency of SauceKeyRenderer is injected via the constructor parameter, enabling automatic dependency resolution at later time.

Injectors

Instances of the bound interfaces are obtainable from injectors, which can be constructed from a collection of modules:

sauce::shared_ptr<Injector> injector = Modules()
	.add(render_module)
	.add(decoder_module)
	.add(model_module)
	.createInjector()
;

Resolving the dependencies

The hello-world example of resolving the dependencies is one simple line:

sauce::shared_ptr<IRender> renderer = injector->get<IRender>();

In this case, SauceKeyRenderer will get resolved and two other dependencies will be automatically instantiated and injected (see test_sauce.cpp).

Mocking and singletons

Sauce allows for different lifetime models of the interface instances. Singletons are possible with the concept of scoped injectors, in which, the instances are shared.

For googlemock getting the resolved instance is crucial, since the expectations are bound to an instance of the mocked class. With automatic dependency resolution and no hacks, the interface IModel would resolve to a new instance in the test. Hence, unless a way to use the shared instance lifetime inside the test is found, the mock is implemented trivially without googlemock.

Summary

This article is once again a short intro into the paradigm of another Dependency Injection library sauce. A more elaborate intro can be read in sauce’s tutorial test suite.

Source: https://github.com/d-led/test-ioc-cpp

More to come…

5 thoughts on “The quest for a c++ Dependency Injection Container library. Part 2, some Sauce

  1. Pingback: Dependency Injection Libraries in C++. Part 1: Wallaroo, Introduction

  2. Pingback: Dependency Injection Libraries in C++. Part 1: dicpp, Introduction

  3. Kris

    Great article addressing dependency injection in C++. I implemented yet another C++ dependency
    injection framework, which recently was proposed for boost – https://github.com/krzysztof-jusiak/di
    library is macro less (free), header only, C++03/C++11/C++14 library providing type safe, compile time, macro free constructor dependency injection.

    Reply
    1. DLed Post author

      Hi Kris! I’m glad you liked it, and thanks for the comment! I’d be glad to try your library out, as I’ve seen it on github, but haven’t got around doing so yet. If you find time, feel free to incorporate it into the test project and make a pull request.

      Reply

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.