I'm working with a project that our architect has decided to use dependency injection for almost everything. We use an IoC container. One of the main issues that I keep coming across when using this pattern is "How do I pass this bit of data here to a different object that will be used later?"
Often, the easiest solution is to mark a specific class as being a "singleton" with our specific injector/container. This is bad for a few reasons. As we all know, singletons are evil and should never be used. Sometimes the class marked as "singleton", should actually have multiple instances when used in different parts of the code. Marking a class as a "singleton" creates a new dependency that we use an injector/container that supports the concept of marking a class as a "singleton".
Another solution is the modify how the injector/container creates the object by writing closures, or other specific logic when the injector is instantiating the object based on what is client is using it and the state of the clients. This is bad because it creates a new dependency of this functionality existing in the injector/container. It also violates the separation of concerns because it now makes the inject/container concerned with several different classes.
Here is an example use case of this problem:
- I am using ClassA early in the application from ClassB. I have some state/data I want to store in ClassA and use it later.
- Some more stuff happens in the application. The object of ClassA is either still on the stack farther down, or that part of the stack no longer exists and maybe there are no references to the object of ClassA. The method of classB may or may not still be on the call stack.
- Later in the application, I want to refer to the state/data of ClassA from ClassC.
Update - I'm adding an example
class ClassA {
private:
shared_ptr<ClassState> state;
shared_ptr<ClassB> b;
public:
ClassA(shared_ptr<ClassState> state, shared_ptr<ClassB> b) {
this->state = state;
this->b = b;
}
void run() {
// do stuff
if (true /* blah blah blah */) {
state->setState(true);
} else {
state->setState(false);
}
// do more stuff
b->run();
}
};
class ClassB {
private:
shared_ptr<ClassC> c;
public:
ClassB(shared_ptr<ClassC> c) {
this->c = c;
}
void run() {
// do stuff
c->run();
// do more stuff
}
};
class ClassC {
private:
shared_ptr<ClassState> state;
public:
ClassC(shared_ptr<ClassState> state) {
this->state = state;
}
void run() {
//This is where I want to use that data that was stored earlier
// in the application
if (state->getState()) {
// do stuff
}
}
};
void main() {
// Create whatever magicaly IOC dependency injector
shared_ptr<ClassA> a = injector.create<ClassA> ();
a->run();
}