繁体   English   中英

Spring的依赖注入是否会破坏信息隐藏?

[英]Doesn't Spring's dependency injection break information hiding?

来自C ++背景我必须掌握Java世界及其框架的复杂性。 看一下DI的弹簧框架,我发现我很难相信我必须制作每个将受DI公众影响的setter功能。 这种要求是否违反了信息隐藏原则?

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

我在这里错过了什么?

我同意你的观点 - 这就是为什么我更喜欢构造函数注入。

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

你(可能)必须制作一个制定者,它会告诉你一些内部细节,但是没有必要制作一个吸气剂。 所以你要透露一些信息,但不是太多; 除了预期目的之外,它对任何事情都没有用。

另外,我建议使用注释和@Autowired,在这种情况下,您不需要创建公共setter。

如果您使用spring注释(@Autowired),您可以使用DI私人成员。

如果你在我的视图中使用松耦合和(单元)可测试弹簧DI会打破不应隐藏的信息。

从未使用@Autowired,我倾向于喜欢在构造函数中使用参数,但有时很难理解参数的含义,特别是如果你有很多参数 - 在这种情况下,我更喜欢使用Effective中描述的“Builder”方法Java的。 构造函数接收构建对象(具有setter),并使用它构造自身。 类的注入属性是final(immutability),“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
   }
}

我这里的问题基本相同:

封装在框架时代

我认为答案可能是构造函数注入。 使用setter公开你的属性使得很难对任何东西进行封装并保持良好的对象状态。

不同意Spring打破封装的观点。 即使你有pojo你已经获得并在课堂上暴露并且第三方消耗你的jar,仍然有可能jar的使用者做同样的事情,这可能是Spring bean配置。 (对于任何其他OOP语言都是如此)

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

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

public void setAge(int age) {
 if ( age < 0 ) {
   throw new AppException("invalid age!");
 }
 this.age=age;
}

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

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

后来,迪恩

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

就个人而言,我不认为使用构造函数注入有助于它,因为它更具概念性。

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

TJ

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM