Spring的依赖注入不会破坏信息隐藏吗?

发布于 2024-07-14 22:54:50 字数 227 浏览 8 评论 0原文

来自 C++ 背景的我必须掌握 Java 的复杂性 世界及其框架。 看看 DI 的 spring 框架我是 发现很难相信我必须让每个 setter 都发挥作用 这将受到 DI 公众的关注。 该要求是否违反了 信息隐藏的原理?

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

我在这里缺少什么?

Coming from a C++ background I have to master the complexity of the Java
world and its frameworks. Looking at the spring framework for DI I am
finding it difficult to believe that I have to make each setter function
which will be subject for DI public. Doesn't that requirement break the
principle of information hiding?

Of course I want spring to be able to set some private parts of my
classes, but I certainly do NOT want every client class to be able to do
the same.

What am I missing here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

好菇凉咱不稀罕他 2024-07-21 22:54:51

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

在我看来,如果你追求松散耦合和(单元)可测试性,Spring DI 就会分解出不应隐藏的信息。

If you use spring annotations (@Autowired) you can DI private members.

If you go for loose coupling and (unit)testability in my view springs DI breaks out information that should not be hidden.

闻呓 2024-07-21 22:54:51

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

框架时代的封装

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

I had basically the same question here:

Encapsulation in the age of frameworks

I think the answer might be constructor injection. Exposing your properties with setters makes it really hard to ecapsulate anything and maintain good object state.

孤单情人 2024-07-21 22:54:51

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

Never used @Autowired, I tend to like using parameters in the constructors but sometimes it's hard to understand what the parameters mean, specially if you have a lot of parameters - in that case, I prefer to use the "Builder" approach described in Effective Java. The constructor receives the build object (which has setters), and constructs itself with it. The injected attributes of the class are final (immutability), the "Builder" class contains setters but not getters (it doesn't need to as we declare it as an inner class of the class that is being constructed), and no setters need to be created just for 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>

Class code:

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
   }
}
琉璃繁缕 2024-07-21 22:54:51

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

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

我得看看@Autowire,不过。

tj

I suppose it is a tradeoff. You reduce hard-wired dependencies, but you potentially expose the guts of your implementation. With the right abstractions, you can reduce that as well, but then you increase the complexity of the code base (for instance, having a generic "Connection" that could be an LDAP connection or an SQL connection).

Personally, I don't think using constructor injection helps with it, either, because it is more conceptual.

I will have to check out @Autowire, tho'.

tj

左秋 2024-07-21 22:54:51

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

Just wanted to mention that I've (inadvertently) posted a more generic version of this question and that it has some further insights into the issue: Must Dependency Injection come at the expense of Encapsulation?

画骨成沙 2024-07-21 22:54:51

不同意 Spring 破坏封装的观点。 即使你有 pojo,你在类中公开了 get 和 set,并且第三方消耗了你的 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;
}

Not agreed with the point that Spring breaks encapsulation. Even if you have pojo where you have get and set exposed in class and third party consumes your jar, still chances that consumer of jar do the same which is possible with the Spring bean configuration. (true for any other OOPs language)

Spring just provides way which can be done through the code and that control moved out of the code (IOC).

Consumer (consider other programmer uses your library), creates bean through the spring configuration, still your code have control. No body stops you to validate input given by the user(spring IOC framework also goes through the same code which is done by other class calling your setter) in setter.

public void setAge(int age) {
 if ( age < 0 ) {
   throw new AppException("invalid age!");
 }
 this.age=age;
}
寄意 2024-07-21 22:54:51

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

之后,
院长

And that is another reason I prefer Guice ;) Both Guice and Spring implement JSR 330 DI spec but with Guice I can inject into my private instance fields with no setters an I really dislike constructor injection as it has seemed harder to refactor. It is also just alot more typing for not much value in my humble opinion.

later,
Dean

放我走吧 2024-07-21 22:54:50

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

I agree with your point - that's why I prefer constructor injection.

2024-07-21 22:54:50

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

If you code to interfaces, you only need to expose setters on the implementations. As you inject the interfaces into other parts of the system, they cannot access the implementation details or state of the objects.

空城缀染半城烟沙 2024-07-21 22:54:50

您(可能)必须创建一个 setter,它将向外部通报您的一些内部细节,但不需要创建一个 getter。 所以你透露了一些信息,但并不是太多; 除了其预期目的之外,它实际上没有任何用处。

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

You (may) have to make a setter, which will inform the outside of some of your internal details, but there's no need to make a getter. So you are revealing some information, but not really too much; it's not really useful for anything but its intended purpose.

Additionally I'd just recommend using annotations and @Autowired, in which case you do not need to make a public setter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文