Consider the (highly simplified) following case:
class Dispatcher {
public:
receive() {/*implementation*/}; // callback
}
class CommInterface {
public:
send() = 0; // call
}
class CommA : public CommInterface {
public:
send() {/*implementation*/};
}
Various classes in the system send messages via the dispatcher. The dispatcher uses a comm to send. Once an answer is returned, the comm relays it back to the dispatcher which dispatches it back to the appropriate original sender. Comm is polymorphic and which implementation to choose can be read from a settings file.
Dispatcher has a dependency on the comm in order to send. Comm has a dependency on dispatcher in order to callback. Therefor there’s a circular dependency here and I can’t seem to implement the dependency injection principle (even after encountering this nice blog post).
Updates:
-
Comm depends on 3rd party code (as
there are various 3rd parties, Comm
is polymorphic). Comm has a receive
function of its own and it relays it
to Dispatcher’s receive function (in
practice there are multiple such
functions with various parameter
sets). A possible call would be:CommA::receive_3(/*parameters set a*/) { /* some parameters manipulation */ dispatcher_ptr->receive_5(/*parameters set b*/); dispatcher_ptr->receive_6(/*parameters set c*/); } - At least currently Dispatcher “knows” which Comm to use using a parameter it receives in its constructor, therefor it can’t initialize Comm in its initialization list. It could have just as easily received a shared_ptr to Comm and be done with it, but that would require first to initialize Comm and Comm requires a pointer to Dispatcher for the callbacks… Of course I could implement a function in Comm named
setDispatcher(Dispather* dispatcher_ptr)but wouldn’t that go against Dependency Injection?
I realized that where many classes use the Dispatcher instance, only the Dispatcher instance uses the CommA instance. Therefore the Dispatcher’s dependency on CommA should not be externalized, i.e. CommA object should not be “injected” to the Dispatcher any more than any other internally defined variable within Dispatcher.
For a minute I thought my question might have been misleading, but then I realized that it originated from a very basic misunderstanding about Dependency Injection. Dependencies should be externalized only if they cannot be internally managed. Therefore I’m leaving this question and this answer for posterity 🙂