Sto lavorando con un progetto che il nostro architetto ha deciso di utilizzare l'iniezione delle dipendenze per quasi tutto. Usiamo un contenitore IoC. Uno dei principali problemi che continuo a riscontrare quando utilizzo questo modello è "Come faccio a passare questo bit di dati qui a un oggetto diverso che verrà utilizzato in seguito?"
Spesso, la soluzione più semplice è quella di contrassegnare una classe specifica come un "singleton" con il nostro specifico iniettore / contenitore. Questo è male per alcune ragioni. Come tutti sappiamo, i singleton sono cattivi e non dovrebbero mai essere usati. A volte la classe contrassegnata come "singleton", in realtà dovrebbe avere più istanze quando viene utilizzata in diverse parti del codice. Contrassegnare una classe come "singleton" crea una nuova dipendenza che usiamo un injector / container che supporta il concetto di marcatura di una classe come "singleton".
Un'altra soluzione è la modifica del modo in cui l'iniettore / contenitore crea l'oggetto scrivendo chiusure o altra logica specifica quando l'iniettore crea un'istanza dell'oggetto in base a ciò che sta utilizzando il client e allo stato dei client. Questo è male perché crea una nuova dipendenza di questa funzionalità esistente nell'iniettore / contenitore. Inoltre viola la separazione delle preoccupazioni perché ora rende l'inject / container interessato a diverse classi diverse.
Ecco un esempio di caso di questo problema:
- Sto utilizzando ClassA nelle prime fasi dell'applicazione da ClassB. Ho alcuni stati / dati che voglio memorizzare in ClassA e usarli in seguito.
- Altre cose si verificano nell'applicazione. L'oggetto di ClassA è ancora nello stack più in basso, o quella parte della pila non esiste più e forse non ci sono riferimenti all'oggetto di ClassA. Il metodo di classB può essere o non essere ancora presente nello stack di chiamate.
- Più avanti nell'applicazione, voglio fare riferimento allo stato / dati di ClassA da ClassC.
Aggiornamento - Sto aggiungendo un esempio
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();
}