I'm trying to exercise the principles of Dependency Injection, and I'm having some difficulty doing so.
I have a function that periodically goes off to my database, retrieves a list of products, and then runs a battery of tests against those products in order to determine their safety.
If one or more of the products is found to be unsafe, I need to issue a recall by instantiating and dispatching a ProductRecall
object.
The function looks something like this: (pseudo-code)
void SafteyInspector::CheckProductSaftey()
{
database.getProducts( list_of_products )
foreach( list_of_products as p )
{
if ( !runBatteryOfTests( p ) )
unsafe_products.insert( p );
}
if ( !unsafe_products.empty() )
{
ProductRecall * recall =
new ProductRecall( unsafe_products ); // Oh no!
recall->dispatch();
}
}
The problem is that I'm "new"-ing a ProductRecall
object right in the middle of my call-graph. This violates the principles of Dependency Injection. As written, I can't test CheckProductSaftey()
without also creating a ProductRecall
object.
However, I can't pass the ProductRecall
object into my SafetyInspector
object, because the SafetyInspector
is the one who determines the list of unsafe products.
I'm using constructor-injection for everything, and I'd like to continue doing so. Note also that I may issue multiple ProductRecalls
at any time, so I can't necessarily just pass a single ProductRecall
object into the SafetyInspector
at construction.
Any suggestions? Thanks!
I think the problem may be with your implementation of ProductRecall
. Specifically, if you can call dispatch()
on a newly created object, it implies that a lot of actual functionality is either hidden inside the ProductRecall
class, or that the ProductRecall
class has static members and/or singletons to give it everything else it needs.
I would recommend creating a class called ProductRecallDispatcher
which handles the intricacies of an actual dispatch. You would then create one of these objects, and pass it to the constructor for SafteyInspector
. This would make your CheckProductSafety
function look as follows:
void SafteyInspector::CheckProductSaftey()
{
database.getProducts( list_of_products )
foreach( list_of_products as p )
{
if ( !runBatteryOfTests( p ) )
unsafe_products.insert( p );
}
if ( !unsafe_products.empty() )
{
recallDispatcher.recall( unsafe_products );
}
}