views:

795

answers:

8

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?

+14  A: 

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

duffymo
+1 on constructor injection. Expresses dependencies a lot stronger and removes the need for 'funny' setters
flq
constructor injection++: Once you create an object it must be ready to use and in a consistent state.
Kalecser
Not all properties may be required for the correct operation of the class. In that case, I always inject them thru setters
oxbow_lakes
@oxbox, that demonstrates the exact difference between the two styles
matt b
boo .
flybywire
@andy - "boo"?
duffymo
+5  A: 

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.

krosenvold
+1 - advocating annotations wherever possible is a good thing. I'm trying to make the jump myself now, but it's hard to break that XML habit.
duffymo
+2  A: 

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.

Kees de Kooter
A: 

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

Travis Jensen
+1  A: 

I had basically the same question here:

http://stackoverflow.com/questions/559953/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.

Andy White
+5  A: 

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.

oxbow_lakes
This answer implies that "coding to interfaces" means that every class must implement a separate interface. This isn't what the principle, as described in the GoF book, means. In reality, it only applies for cases where you need, or already have, two separate object types, one for the abstraction (interface) and another for one implementation of that abstraction.
Rogerio
I think you are likely to find that the classes which need to be injected into each other in a common Spring application are **service** classes, such as `Dao`s etc. I have found that a large number of these could conceivably have alternate implementations
oxbow_lakes
Yes, when you have multiple implementations the "code to the interface, not the implementation" principle does apply. But saying things like "if you code to interfaces ..." without a clear context is misleading, and can easily be mis-interpreted by less experienced developers. Overuse of separate interfaces causes great harm, IMO.
Rogerio
What harm? Admittedly in bloats the codebase but starting with an interface rather than an implementation is positive from the aspect of forcing you to think about what abstractions exist within the problem you are solving
oxbow_lakes
A: 

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: http://stackoverflow.com/questions/1005473/must-dependency-injection-come-at-the-expense-of-encapsulation

urig
+1  A: 

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
   }
}
Ravi Wallau