14

来自 C++ 背景的我必须掌握 Java 世界及其框架的复杂性。查看 DI 的 spring 框架,我发现我很难相信我必须将每个 setter 函数都公开给 DI。这个要求不是破坏了信息隐藏的原则吗?

当然,我希望 spring 能够设置我的类的一些私有部分,但我当然不希望每个客户端类都能够这样做。

我在这里想念什么?

4

10 回答 10

15

我同意你的观点——这就是我更喜欢构造函数注入的原因。

于 2009-03-09T20:13:01.997 回答
6

如果您对接口进行编码,则只需要在实现上公开设置器。当您将接口注入系统的其他部分时,它们无法访问对象的实现细节或状态。

于 2009-03-09T20:47:21.897 回答
5

您(可能)必须制作一个 setter,它将通知外部您的一些内部细节,但没有必要制作一个 getter。所以你透露了一些信息,但不是太多;除了其预期目的之外,它对任何事情都没有真正的用处。

此外,我只建议使用注释和@Autowired,在这种情况下,您不需要创建公共设置器。

于 2009-03-09T20:13:43.553 回答
3

如果您使用弹簧注释(@Autowired),您可以 DI 私有成员。

在我看来,如果您追求松散耦合和(单元)可测试性,那么 DI 会弹出不应隐藏的信息。

于 2009-03-09T20:14:46.780 回答
1

我在这里基本上有同样的问题:

框架时代的封装

我认为答案可能是构造函数注入。用 setter 暴露你的属性使得封装任何东西并保持良好的对象状态变得非常困难。

于 2009-03-09T20:33:11.230 回答
1

从未使用过@Autowired,我倾向于在构造函数中使用参数,但有时很难理解参数的含义,特别是如果您有很多参数 - 在这种情况下,我更喜欢使用 Effective 中描述的“Builder”方法爪哇。构造函数接收构建对象(具有设置器),并用它构造自己。类的注入属性是最终的(不变性),“Builder”类包含setter但不包含getter(它不需要,因为我们将其声明为正在构造的类的内部类),并且不需要setter仅为 Spring 创建:

<bean id="runnable" class="MyClass">
   <constructor-arg>
     <bean class="MyClass$Builder">
       <property name="p1" value="p1Value"/>
       <property name="p2" value="p2Value"/>
       <property name="p3" value="p3Value"/>
       <property name="p4" value="p4Value"/>
     </bean>
   </constructor-arg>
</bean>

班级代码:

public class MyClass {
   private final String p1;
   private final String p2;
   private final String p3;
   private final String p4;
   public MyClass(Builder builder) {
      this.p1 = builder.p1;
      this.p2 = builder.p2;
      this.p3 = builder.p3;
      this.p4 = builder.p4;
   }

   ...

   public static class Builder {
      private String p1;
      private String p2;
      private String p3;
      private String p4;
      public void setP1(String p1) {
         this.p1 = p1;
      }
      ... and so on
   }
}
于 2009-06-18T19:18:14.647 回答
0

我想这是一个权衡。你减少了硬连线的依赖,但你可能会暴露你的实现的胆量。使用正确的抽象,您也可以减少这种情况,但随后会增加代码库的复杂性(例如,具有可以是 LDAP 连接或 SQL 连接的通用“连接”)。

就个人而言,我认为使用构造函数注入也无济于事,因为它更具概念性。

我将不得不检查@Autowire,tho'。

tj

于 2009-03-09T20:32:03.027 回答
0

只是想提一下,我(无意中)发布了这个问题的更通用版本,并且对这个问题有一些进一步的见解:依赖注入必须以封装为代价吗?

于 2009-06-18T19:08:23.667 回答
0

不同意 Spring 打破封装的观点。即使你有 pojo,你已经在类中公开了并且第三方使用了你的 jar,jar 的消费者仍然有可能做同样的事情,这在 Spring bean 配置中是可能的。(适用于任何其他 OOP 语言)

Spring 只是提供了可以通过代码完成的方法,并且该控件移出代码(IOC)。

消费者(考虑其他程序员使用您的库),通过 spring 配置创建 bean,您的代码仍然可以控制。没有人阻止您在 setter 中验证用户给出的输入(spring IOC 框架也通过其他类调用您的 setter 完成的相同代码)。

public void setAge(int age) {
 if ( age < 0 ) {
   throw new AppException("invalid age!");
 }
 this.age=age;
}
于 2012-04-13T13:27:45.870 回答
0

这也是我更喜欢 Guice 的另一个原因;) Guice 和 Spring 都实现了 JSR 330 DI 规范,但是使用 Guice,我可以在没有设置器的情况下注入我的私有实例字段,我真的不喜欢构造函数注入,因为它似乎更难重构。在我的拙见中,它也只是更多的打字而没有多大价值。

后来,迪恩

于 2012-04-27T13:20:08.280 回答