5

我的同事和我的争执已经持续了几个星期。我想听听社区对此的看法。

我们在应用程序中使用 guice。在此应用程序的 UI 部分,我更喜欢通过 DI 和自定义注释(也称为工厂的位置)实例化所有字段和组件,并将它们连接到 buildUI 方法中。

看起来如下:

我的方法:

@Inject
@PreConfigured(caption="foo", width="100%")
Label field;

private void buildUI() {
   this.addComponent(field);
}

我还为数据绑定和 i18n 编写了一些注释。

我的同事是这样做的:

他的方法:

private Label field;

private void buildUI() {
   field = new Label();
   field.setCaption("foo");
   field.setWidth("100%");
   this.addComponent(field);
}

这里的代码可能很长。考虑到数据绑定和其他主题,第二个代码可能会变得更长,而我的方法只是另一个注释。

我的理由是:

  1. 配置所有组件的行为和外观的中心位置
  2. 代码重用
  3. 性能 - 在长时间运行的应用程序中,组件的初始化代码变得“热”,jit 对其进行了更多优化。
  4. 更具可读性。

他的理由是:

  1. 可读性
  2. 视图代码不会散落在各处。
  3. 该课程没有 DI
  4. 依赖注入的灵活性被高估了,尤其是在注入具体类的情况下。
  5. 使用 DI 的唯一有效方法是构造函数注入。

但我也阅读了 Fowler 的一些文章,他在其中指出,setter 注入(用场注入代替)是一个糟糕的设计决策。但是在其他项目中没有任何重用的视图呢?

现场注入是一个糟糕的设计吗?或者上面介绍的另一种方式更优雅?

亲切的问候克里斯蒂安

PS:我知道讨论只是基于意见开始的,但这是一个长期持续的讨论(setter 与构造函数注入),这可能值得放手。

4

3 回答 3

3

Disclaimer: since this is kind of a subjective question, I'll also make some subjective claims in this answer, based on personal preference. Here are my two cents:

Both approaches look bad to me.

Yours is bad because:

  • You have all bindings in a module. Think how large can this module grow, specially if there are lots of screens. Think about the mantainability implications of this: Now a programmer wanting to change a single screen will have to

    1- Know the DI framework
    2- Find the module where the bindings for this screen are defined.
    3- Scroll down to find the binding.
    4- Make the change in the module, maybe also in the screen.
    5- Commit changes for the module class, maybe also for the screen class.
    
  • Using DI means using reflection, which is going to be slower than not using it.

  • Makes your code depend on a 3rd party code (the DI framework)
  • Part of the layout is still hardcoded in the screen (what are the container views and what do they contain), and part is in another module. The single-responsibility principle is broken.
  • Annotations are "dirty": Now the source files are written in two different languages. It is less readable and there can also be issues when using automatic code analysis tools.
  • Hard to write unit tests (and btw the tests should use the DI framework to run, which is a bad thing, and slower specially if there are a lots of tests).

Your colleage's approach is of course flawed, since it contains hard dependencies. This might be acceptable for screens, though. I think DI is ok for big things (like injecting a service with a parser implementation, injecting controllers, daos, loggers), but I won't use it for views, and I'd rather stick to constructor injection. So (in Android) I'd just define the views in xml and code the view-controller part in the Activity class, which is the way you are supposed to do it.

于 2013-09-18T14:08:56.560 回答
1

我认为您的问题并不适合 StackOverflow(查看常见问题解答),但我可以向您介绍我的想法。

我支持你在这个问题上的想法,因为你似乎已经在这个项目中使用了 DI,那么你为什么不使用它提供的功能呢?

我对你的理由的评论:

  1. 如果可能的话,我更喜欢对所有配置使用 java 代码(因为它可以很容易地重构)。如果 java 代码太冗长,我更喜欢注释(这是你的情况),我会做任何事情来避免xml/yaml/任何其他标记语言配置。
  2. 您实际上可以重用您的注释,这将许多样板代码简化为简洁易读的注释。硬编码的值不可重用,但可重用性在这里不适用
  3. 我没有对您的代码进行基准测试(因为我没有代码库),但是使用注释通常涉及反射,这肯定比调用 setter 慢。所以我认为如果这成为性能瓶颈,你会摸不着头脑如何处理涉及反射的部分
  4. 确实。我的意思是将您的示例与他的示例进行比较。没有一个理智的人会说阅读 4 行充满语法的代码会比阅读更易读@PreConfigured(caption="foo", width="100%")

他的观点:

  1. 中解释了4.
  2. 他所说的“四处散落”是什么意思?在您的情况下,注释始终位于字段上,但如果您以编程方式对其进行初始化,则代码可以在任何地方。那是分散的。
  3. 如果您已经使用 Guice,那么不使用 DI 是没有意义的。他对DI有问题吗?
  4. 这就像“辱骂”。没有意义。给他看保罗格雷厄姆写的这篇文章。
  5. 然后想想一个有 20 个字段的对象。当然,拥有 20 个字段已经是一种代码味道,但是超过 4-5 个参数的任何东西都很难看。我个人更喜欢 setter 注入,因为它不涉及private使用反射篡改字段,也不涉及具有 8-10 个参数的构造函数。如果您想要不可变对象,您可以使用该Builder模式,如果您想要单例,您可以放心 Spring(我认为 Guice 具有相同的概念)单例范围对您来说很好。顺便说一句,这是常识:如果这是唯一有效的方法,就没有其他方法了,对吧?
于 2013-09-18T12:37:01.157 回答
0

字段注入是比单独调用设置器更好的设计。你为什么要花时间打电话给特定的二传手。依赖注入的全部意义在于避免业务逻辑中设置器的样板代码。

于 2013-09-18T10:01:20.540 回答