Dependency Inversion/Injection

Started by
3 comments, last by PrestoChung 12 years, 8 months ago
Looking for ideas on dependence in a game engine.
It would be nice to be able to explicitly plan dependencies before hand. But is this possible? Any resources on this would be appreciated.

What I usually end up with is:

-Game objects are 'managed' by higher level code
-Game objects are composed of lower level components

This seems to result in the higher level code has to know about all the differentiated implementations of the lower-level parts (resulting in switches that need to be changed when adding lower level code).

One explanation I have seen is to provide interfaces between different parts of the code that doesn't rely on the specific implementation. I think this was using C#. In C++, can this be achieved by using a 'base' class as the interface to the derived classes? So far I have avoided using virtual functions but maybe it is too limiting without.

Any thoughts on this are appreciated.
Advertisement
If you do DI all the way down, you eventually get to all the way out to a single factory that constructs almost every component of the application. Of course, you can break that factory down into sensible modules if you want, but conceptually, that's what you get.

Though, I'm not sure I understand what you're talking about when you say that you have switches that need to be changed when adding lower level code.
DI and interfaces are useful together, but they don't need each other.

In C++, you can get "lightweight" interfaces by using little value wrappers, but they aren't entirely free - they incur developer overhead (lots of boilerplate).

For example:

// Big Dependency Header

class BigDependency
{
public:
void functionA();

void functionB();
};

// ******************************
// Light Dependency A Header

class BigDependency;

class LightDependencyA
{
public:
LightDependencyA(BigDependency *big) : big(big)
{
}

void functionA(); // Implementation: big->functionA();

private:
BigDependency *big;
};

// ******************************
// Light Dependency B Header

class BigDependency;

class LightDependencyB
{
public:
// Allows implicit conversion, if you want
LightDependencyB(BigDependency &big) : big(&big)
{
}

void functionB(); // Implementation: big->functionB();

private:
BigDependency *big;
};

// ******************************
// Elsewhere...

void foo(LightDependencyA a)
{
a.functionA();
}

void bar(LightDependencyB b)
{
b.functionB();
}

void example()
{
BigDependency big;

LightDependencyA a(&big);

foo(a);

bar(big);
}

DI and interfaces are useful together, but they don't need each other.

In C++, you can get "lightweight" interfaces by using little value wrappers, but they aren't entirely free - they incur developer overhead (lots of boilerplate).


Fortunately, unlike Java or C#, where everything must be a class, C++ has free function and namespaces, removing the need for most boilerplate. Since DI classes should be transient and stateless by design, their class invariants are mostly enforced by caller.

Factories and all the extra crud is a workaround around language design, it's not needed as such.

The header/implementation separation in C/C++ also makes mocks/stubs possible without resorting to all the usual overhead.
Slavik81
A switch example:
Let's say we're dealing with game objects that are a collection of components.
We want to construct a game object by providing a list of component types

Object( std::list<ComponentId> );

The way I would deal with that is to iterate over the list of ComponentId s and initialize each one within a switch.

rip-off
I think this is the direction I'm headed. One could do something similar with static functions as well since this doesn't rely on inheritance (static virtual functions are not possible as far as I know?)?

Antheus
Not sure what mocks/stubs are, is there a good explanation of the subject you could point me to?

Also, are you all using DI to mean both Injection AND Inversion?

This topic is closed to new replies.

Advertisement