【问题标题】:Doesn't Spring's dependency injection break information hiding?Spring的依赖注入不会破坏信息隐藏吗?
【发布时间】:2010-10-12 06:50:24
【问题描述】:

来自 C++ 背景,我必须掌握 Java 的复杂性 世界及其框架。看看我的 DI 的 spring 框架 很难相信我必须让每个 setter 函数 这将是 DI 公众的主题。这个要求不会破坏 信息隐藏原理?

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

我在这里错过了什么?

【问题讨论】:

    标签: java spring dependency-injection encapsulation


    【解决方案1】:

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

    【讨论】:

    • 构造函数注入+1。更强烈地表达依赖关系并消除对“有趣”设置器的需求
    • 构造函数注入++:一旦你创建了一个对象,它就必须准备好使用并且处于一致的状态。
    • 类的正确操作可能不需要所有属性。在这种情况下,我总是通过 setter 注入它们
    • @oxbox,这表明了两种风格之间的确切区别
    • 嘘。
    【解决方案2】:

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

    【讨论】:

    • 这个答案意味着“编码到接口”意味着每个类都必须实现一个单独的接口。这不是 GoF 书中描述的原则的含义。实际上,它仅适用于您需要或已经拥有两种不同对象类型的情况,一种用于抽象(接口),另一种用于该抽象的一种实现。
    • 我想你很可能会发现在一个普通的Spring应用中需要相互注入的类是service类,比如Daos等。我发现其中很多可以想象有替代实现
    • 是的,当您有多个实现时,“代码到接口,而不是实现”原则确实适用。但是在没有明确上下文的情况下说“如果你编写接口......”之类的话会产生误导,并且很容易被经验不足的开发人员误解。 IMO,过度使用单独的接口会造成很大的危害。
    • 有什么害处?诚然,代码库膨胀,但从接口而不是实现开始是积极的,这会迫使您考虑您正在解决的问题中存在哪些抽象
    【解决方案3】:

    您(可能)必须制作一个 setter,它会将您的一些内部细节告知外部,但没有必要制作一个 getter。所以你透露了一些信息,但并没有太多;除了它的预期目的之外,它并没有真正的用处。

    另外我只推荐使用注解和@Autowired,在这种情况下你不需要创建一个公共的setter。

    【讨论】:

    • +1 - 尽可能提倡注释是一件好事。我现在正在尝试自己进行跳跃,但很难打破 XML 习惯。
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

      Encapsulation in the age of frameworks

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

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

          我得去看看@Autowire,不过。

          tj

          【讨论】:

            【解决方案8】:

            只是想提一下,我(无意中)发布了这个问题的更通用版本,并且对这个问题有一些进一步的见解:Must Dependency Injection come at the expense of Encapsulation?

            【讨论】:

              【解决方案9】:

              不同意 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;
              }
              

              【讨论】:

                【解决方案10】:

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

                后来, 院长

                【讨论】:

                  猜你喜欢
                  • 2017-02-16
                  • 1970-01-01
                  • 2011-01-17
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-12-29
                  • 1970-01-01
                  • 2019-02-18
                  • 2017-09-12
                  相关资源
                  最近更新 更多