依赖注入:将调用图与构造图分离
我正在尝试练习依赖注入原则,但我在做时遇到了一些困难所以。
我有一个功能可以定期访问我的数据库,检索产品列表,然后针对这些产品运行一系列测试以确定它们的安全性。
如果发现一个或多个产品不安全,我需要通过实例化和分派 ProductRecall
对象来发出召回。
该函数看起来像这样:(伪代码)
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();
}
}
问题是我在调用图的中间“新建”了一个 ProductRecall
对象。 这违反了依赖注入的原则。 正如所写,如果不创建 ProductRecall
对象,我就无法测试 CheckProductSafey()
。
但是,我无法将 ProductRecall
对象传递到我的 SafetyInspector
对象中,因为 SafetyInspector
是确定不安全产品列表的对象。
我对所有事情都使用构造函数注入,并且我想继续这样做。 另请注意,我可能随时发出多个 ProductRecalls
,因此我不一定在构造时将单个 ProductRecall
对象传递到 SafetyInspector
中。
有什么建议么? 谢谢!
I'm trying to exercise theprinciples 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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为问题可能出在您的
ProductRecall
实现上。 具体来说,如果您可以对新创建的对象调用dispatch()
,则意味着许多实际功能要么隐藏在ProductRecall
类中,要么>ProductRecall
类具有静态成员和/或单例,可以为其提供所需的一切。我建议创建一个名为 ProductRecallDispatcher 的类来处理实际调度的复杂性。 然后,您将创建这些对象之一,并将其传递给
SafetyInspector
的构造函数。 这将使您的CheckProductSafety
函数如下所示:I think the problem may be with your implementation of
ProductRecall
. Specifically, if you can calldispatch()
on a newly created object, it implies that a lot of actual functionality is either hidden inside theProductRecall
class, or that theProductRecall
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 forSafteyInspector
. This would make yourCheckProductSafety
function look as follows:我认为您实际上需要想出某种
ProductRecallFactory
来代替。 注入容器支持某种工厂风格的接口是相当常见的,或者您可能只是希望让您的 SafetyInspector 容器感知。编辑:通过“容器感知”,我指的是按照 COM 的 IObjectWithSite 的方式实现一些接口,以便您的对象可以回调到其父对象。 这是一种较弱的依赖注入形式,它部分地撤销了控制反转。 如果您手动执行依赖项注入,请务必注入工厂对象。
I think you actually need to conjure up some sort of
ProductRecallFactory
to pass in instead. It's fairly common for injection containers to support some sort of factory-style interface, or you may just wish to make your SafetyInspector container-aware.EDIT: by "container-aware" I'm referring to implementing some interface along the lines of COM's
IObjectWithSite
, so that your object can call back to its parent. It's a weaker form of dependency injection which partially undoes the inversion of control. If you're doing the dependency injection manually, by all means inject a factory object.