Easy to do in .NET with a generic Dictionary
- the entry point of the code that uses the business layer (an executable for instance). This is production code and it has to create the object connecting to the real database.
{
// Create the concrete DataLayer object
DataLayer dataLayer;
// Register it with the resolver
Resolver::Register<IDataLayer>(dataLayer);
BusinessStuff businessStuff;
businessStuff.DoStuff();
return 0;
}
- the unit-test code. The IDataLayer object in that case is a fake object that doesn't connect to the real database and therefore makes unit-tests easily reproducible and fast.
{
// Arrange
// Create the concrete DataLayer object
FakeDataLayer dataLayer;
// Register it with the resolver
Resolver::Register<IDataLayer>(dataLayer);
BusinessStuff businessStuff;
// Act
businessStuff.DoStuff();
// Assert
dataLayer.AssertStuffWasDone();
}
The Resolver class has two methods Register and Resolve. Here is the code for the Resolver class (very straightforward):
#include
#include
using namespace std;
///
/// Allows you to Register and Resolve global objects
///
class Resolver
{
static map<string, void* > typeInstanceMap;
public:
template<class T> static void Register(const T& object)
{
typeInstanceMap[typeid(T).name()] = (void*)&object;
}
template<class T> static T& Resolve()
{
return *((T*)typeInstanceMap[typeid(T).name()]);
}
};
This is a just a starting point. In production Resolver could do with methods such as Unregister(), IsRegistered(), UnregisterAll()...
An IoC container is one way to do dependency injection. Other ways include:
- pass the injected object using the constructor
- pass the injected object using a setter method
I tried all 3 methods and I find the IoC approach scales rather well. I've used it for 10 months in a production project and it works nicely with unit tests.
Resources:
Jean-Paul Boodhoo on the gateway pattern
Roll your own IoC container (dnrTV)
The Art of Unit-Testing where Roy Osherove tells everything about dependency injection and fake objects.