依赖注入:将调用图与构造图分离

发布于 2024-07-18 22:21:41 字数 1146 浏览 7 评论 0原文

我正在尝试练习依赖注入原则,但我在做时遇到了一些困难所以。

我有一个功能可以定期访问我的数据库,检索产品列表,然后针对这些产品运行一系列测试以确定它们的安全性。

如果发现一个或多个产品不安全,我需要通过实例化和分派 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

歌枕肩 2024-07-25 22:21:41

我认为问题可能出在您的 ProductRecall 实现上。 具体来说,如果您可以对新创建的对象调用 dispatch(),则意味着许多实际功能要么隐藏在 ProductRecall 类中,要么 >ProductRecall 类具有静态成员和/或单例,可以为其提供所需的一切。

我建议创建一个名为 ProductRecallDispatcher 的类来处理实际调度的复杂性。 然后,您将创建这些对象之一,并将其​​传递给 SafetyInspector 的构造函数。 这将使您的 CheckProductSafety 函数如下所示:

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 );
  }
}

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 );
  }
}
路弥 2024-07-25 22:21:41

我认为您实际上需要想出某种 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文