5

也许我在文档中错过了它,但我想知道我应该如何处理“帮助对象”?

代码示例:

public Path dijkstra(Node startNode, Node endNode) {
    Set<Node> nodesToInspect = new HashSet<Node>();  // should this Object be injected?
    Path path = new Path();  // and this one?

    while (!nodesToInspect.isEmpty()) {
        // some logic like:
        path.add(currentNode);

    }

    return path;
}

我应该注入所有东西还是应该在某个时候说算法“最清楚”它需要什么?我应该尝试消除每一个“新”吗?或者一些对象创建是否正常,例如 HashSet、ArrayList 等 API 类。

4

3 回答 3

2

在用依赖注入替换简单之前new,您需要问自己“我为什么要这样做?” ...“它有什么真正的好处?”。如果答案是“我不知道”或“什么都没有”,那么您不应该这样做。

在这种情况下,我看不出在您的示例代码的第一种情况下使用 DI 没有真正的好处。该方法之外的任何东西都不需要知道内部集合是如何表示的……甚至不需要知道它的存在。

您应该问的另一个问题是是否有更简单、更明显的方法来实现目标。例如,对path变量使用 DI 的(最可能的)目的是允许应用程序使用不同的Path类。但简单Path的方法是将实例dijkstra作为显式参数传递给方法。您甚至可以使用重载来使这更可口;例如

public Path dijkstra(Node startNode, Node endNode) {
    return dijkstra(startNode, endNode, new Path());
}

public Path dijkstra(Node startNode, Node endNode, Path path) {
    ...
}

new最后要考虑的是 DI(在 Java 中)在某种程度上涉及反射,并且不可避免地比使用或工厂对象/方法的经典方法更昂贵。如果您不需要 DI 的额外灵活性,则不应该为此付费。


我刚刚注意到您所指的两个变量是局部变量。我不知道任何允许您注入局部变量的 DI 框架......

于 2012-12-19T02:19:03.410 回答
1

Remember the design principle: "Encapsulate what changes often" or "encapsulate what varies". As the engineer, you know best what is likely to change. You wouldn't want to hard-code the year 2012 into code that will live until next decade, but you also wouldn't want to make "Math.PI" a configuration setting either--that'd be extra overhead and configuration that you'd never need to touch.

That principle doesn't change with dependency injection.

Are you writing one algorithm and you know which implementation of Set you need, like in your Dijkstra example? Create your object yourself. But what if your co-worker is soon to deliver a fantastic new implementation of Set optimized for your use-case, or what if you are experimenting with different collection implementations for benchmarking? Maybe you'll want to inject a Provider until the dust settles. That's less likely for collections, but maybe it's more likely for similar disposable objects you might think of as "helper objects".

Suppose you're choosing between different types of CreditCardAuthService that may vary at runtime. Great case for injection. But what if you've signed a five-year contract and you know your code is going to be replaced long before then? Maybe hard-coding to one service makes more sense. But then you have to write some unit tests or integration tests and you really don't want to use a real credit card backend. Back to dependency injection.

Remember: code is malleable. Someday you may decide that you need to rip out your hard-coded HashSet and replace it with something else, which is fine. Or maybe you'll discover that you need your service to vary often enough that it should be Guice-controlled, and then you add a constructor parameter and a binding and call it a day. Don't worry about it too much. Just keep in mind that just because you have a hammer, not every problem is a Provider<WoodFasteningService>.

于 2012-12-19T06:33:01.057 回答
0

在使用 DI 时,我更愿意尽可能避免使用“新”。您在容器外部创建的每个实例(例如 guice 注入器)都不能重构为使用注入(如果您的“路径”实例应该获得一个通过配置注入的字符串“根”......并且您也不能在这些对象上使用拦截器。因此,除非它是纯 Entity-Pojo,否则我一直使用 Provides/Inject。它也是控制反转(好莱坞)模式和可测试性的一部分……如果您需要在 Junit 中模拟 Path 或 Set 怎么办?让它们注入(在这种情况下是提供者),之后您可以轻松地切换具体实现。

于 2012-12-19T15:12:21.210 回答