views:

986

answers:

17

If I understand correctly, the typical mechanism for Dependency Injection is to inject either through a class' constructor or through a public property (member) of the class.

This exposes the dependency being injected and violates the OOP principle of encapsulation.

Am I correct in identifying this tradeoff? How do you deal with this issue?

Please also see my answer to my own question below.

+4  A: 

It doesn't violate encapsulation. You're providing a collaborator, but the class gets to decide how it is used. As long as you follow Tell don't ask things are fine. I find constructer injection preferable, but setters can be fine as well as long as they're smart. That is they contain logic to maintain the invariants the class represents.

Jason Watkins
Thanks for your reply and for the link. Can you elaborate on why you think this doesn't violate encapsulation? If you take a look here: http://tinyurl.com/cscynq , you'll find almost every tenet of encapsulation is violated by having a dependency exposed publicly.
urig
Because it... doesn't? If you have a logger, and you have a class that needs the logger, passing the logger to that class does not violate encapsulation. And that's all dependency injection is.
jrockway
I think you misunderstand encapsulation. For example, take a naive date class. Internally it might have day, month and year instance variables. If these were exposed as simple setters with no logic, this would break encapsulation, since I could do something like set month to 2 and day to 31. On the other hand, if the setters are smart and check the invariants, then things are fine. Also notice that in the latter version, I could change the storage to be days since 1/1/1970, and nothing that used the interface need be aware of this provided I appropriately rewrite the day/month/year methods.
Jason Watkins
DI definitely does violate encapsulation/information hiding. If you turn a private internal dependency into something exposed in the public interface of the class, then by definition you have broken the encapsulation of that dependency.
Rogerio
I have a concrete example where I think encapsulation is compromised by DI. I have an FooProvider that gets "foo data" from the DB and a FooManager that caches it and calculates stuff on top of the provider. I had consumers of my code mistakenly going to the FooProvider for data, where I'd rather have had it encapsulated away so they are only aware of the FooManager. This is basically the trigger for my original question.
urig
@urig - can FooManager work without a connection string? If not, it hasn't really encapsulated the FooProvider.
Jeff Sternal
+4  A: 

A good depenancy injection container/system will allow for constructor injection. The dependant objects will be encapsulated, and need not be exposed publicly at all. Further, by using a DP system, none of your code even "knows" the details of how the object is constructed, possibly even including the object being constructed. There is more encapsulation in this case since nearly all of your code not only is shielded from knowledge of the encapsulated objects, but does not even participate in the objects construction.

Now, I am assuming you are comparing against the case where the created object creates its own encapsulated objects, most likely in its constructor. My understanding of DP is that we want to take this responsibility away from the object and give it to someone else. To that end, the "someone else", which is the DP container in this case, does have intimate knowledge which "violates" encapsulation; the benefit is that it pulls that knowledge out of the object, iteself. Someone has to have it. The rest of your application does not.

I would think of it this way: The dependancy injection container/system violates encapsulation, but your code does not. In fact, your code is more "encapsulated" then ever.

Bill
If you have a situation where the client object CAN instantiate its dependencies directly, then why not do so? It's definitely the simplest thing to do, and does not necessarily reduce testability.Besides the simplicity and better encapsulation, this also makes it easier to have stateful objects instead of stateless singletons.
Rogerio
+11  A: 

It's a good question - but at some point, encapsulation in its purest form needs to be violated if the object is ever to have its dependency fulfilled. Some provider of the dependency must know both that the object in question requires a Foo, and the provider has to have a way of providing the Foo to the object.

Classically this latter case is handled as you say, through constructor arguments or setter methods. However, this is not necessarily true - I know that the latest versions of the Spring DI framework in Java, for example, let you annotate private fields (e.g. with @Autowired) and the dependency will be set via reflection without you needing to expose the dependency through any of the classes public methods/constructors. This might be the kind of solution you were looking for.

That said, I don't think that constructor injection is much of a problem, either. I've always felt that objects should be fully valid after construction, such that anything they need in order to perform their role (i.e. be in a valid state) should be supplied through the constructor anyway. If you have an object that requires a collaborator to work, it seems fine to me that the constructor publically advertises this requirement and ensures it is fulfilled when a new instance of the class is created.

Ideally when dealing with objects, you interact with them through an interface anyway, and the more you do this (and have dependencies wired through DI), the less you actually have to deal with constructors yourself. In the ideal situation, your code doesn't deal with or even ever create concrete instances of classes; so it just gets given an IFoo through DI, without worrying about what the constructor of FooImpl indicates it needs to do its job, and in fact without even being aware of FooImpl's existance. From this point of view, the encapsulation is perfect.

This is an opinion of course, but to my mind DI doesn't necessarily violate encapsulation and in fact can help it by centralising all of the necessary knowledge of internals into one place. Not only is this a good thing in itself, but even better this place is outside your own codebase, so none of the code you write needs to know about classes' dependencies.

Andrzej Doyle
Thanks for the detailed reply :) Would you know of a DI framework for .net that allows for private members to be injected into? Might Spring.net support this? How significant might the impact on performance be, as this mechanism relies on reflection?
urig
Good points.I advise against using @Autowired on private fields; that makes the class hard to test; how do you then inject mocks or stubs?
lumpynose
I disagree. DI does violate encapsulation, and this can be avoided. For example, by using a ServiceLocator, which obviously does not need to know anything about the client class; it only needs to know about the implementations of the Foo dependency.But the best thing, in most cases, is to simply use the "new" operator.
Rogerio
@Rogerio - Arguably any DI framework acts exactly like the ServiceLocator you describe; the client doesn't know anything specific about Foo implementations, and the DI tool doesn't know anything specific about the client. And using "new" is much worse for violating encapsulation, as you need to know not only the exact implementation class, but also the exact classes *and* instances of all the dependencies it needs.
Andrzej Doyle
Using "new" to instantiate a helper class, which often isn't even public, promotes encapsulation. The DI alternative would be to make the helper class public and add a public constructor or setter in the client class; both changes would break the encapsulation provided by the original helper class.
Rogerio
A: 

There's a huge advantage to injecting the objects using the constructor. Very often that design will lead to using the strategy pattern getting a lot of flexibility but if you really wish to hide the objects there's nothing DIish stoping you from doing that.

E.g:

class bar{
  bar(){
    _innerFoo ? new Foo();
  }
}

with DI you could just do

bar()
{
   _innerFoo = ServiceContainer.Get<Foo>();
}

(Where ServiceContain.Get() tell your DI mechanism to construct a Foo object as configured in your DI setup)

Rune FS
Actually, explicitly using the service locator (or container in this example) to get dependencies is discouraged, as it is in itself a hard dependency on the container. The main point behind an IoC/DI container is that it injects dependencies implicitly by creating objects as needed, and tracking their lifecycle.
Avish
I wouldn't in this particular case embed the container/locator. Personaly I don't think that the stated concern is avlid there's no violation of encapsulation (as stated above) but the above idea doesn't (even tho the implementation does) impose a hard dependency. Give the locator/container to the constructor and declare a suitable interface :) (which i wouldn't do either)as a good reference take a look at http://martinfowler.com/articles/injection.html. Actually making a hard reference not that that in it self is an argument for doing so
Rune FS
The above can be obtained with no hard dependency on the service locator/IoC Container. I'd usually wrap it anyways but there are times where you can't avoid to embed your (wrapped) service locator/IoC Container. Try using dependency injection for an ASP.NET page unless you are willing to do some serious work with handlers or similar having constructor injection or property injection external to the ASPX page is not an option. Substitute the notion of a page with a service and you get similar problems
Rune FS
The point Avish is making is that you're not doing IoC in these cases. Sure, the ASPX situation can warrant using this technique, the "inversion" is gone, and you're just doing service location. The fact that there's an IoC container under there doesn't make it IoC/dependency injection.
Nicholas Blumhardt
A: 

I struggled with this notion as well. At first, the 'requirement' to use the DI container (like Spring) to instantiate an object felt like jumping thru hoops. But in reality, it's really not a hoop - it's just another 'published' way to create objects I need. Sure, encapsulation is 'broken' becuase someone 'outside the class' knows what it needs, but it really isn't the rest of the system that knows that - it's the DI container. Nothing magical happens differently because DI 'knows' one object needs another.

In fact it gets even better - by focusing on Factories and Repositories I don't even have to know DI is involved at all! That to me puts the lid back on encapsulation. Whew!

n8wrl
As long as DI is in charge of the entire chain of instantiation, then I agree that encapsulation sort of occurs. Sort of, because the dependencies are still public and can be abused.But when somewhere "up" in the chain someone needs to instantiate an object without them using DI (maybe they're a "third party") then it gets messy. They are exposed to your dependencies and might be tempted to abuse them. Or they might not want to know about them at all.
urig
+1  A: 

Having struggled with the issue a little further, I am now in the opinion that Dependency Injection does (at this time) violate encapsulation to some degree. Don't get me wrong though - I think that using dependency injection is well worth the trade off in most cases.

The case for why DI violates encapsulation becomes clear when the component you are working on is to be delivered to an "external" party (think of writing a library for a customer).

When my component requires sub-components to be injected via the constructor (or public properties) there's no guarantee for "preventing users from setting the internal data of the component into an invalid or inconsistent state". At the same time it cannot be said that "users of the component (other pieces of software) only need to know what the component does, and cannot make themselves dependent on the details of how it does it". Both quotes are from wikipedia.

To give a specific example: I need to deliver a client-side DLL that simplifies and hides communication to a WCF service (essentially a remote facade). Because it depends on 3 different WCF proxy classes, If I take the DI approach I am forced to expose them via the constructor. With that I expose the internals of my communication layer which I am trying to hide.

Generally I am all for DI. In this particular (extreme) example, it strikes me as dangerous.

urig
+2  A: 

Yes, DI violates encapsulation (also known as "information hiding").

But the real problem comes when developers use it as an excuse to violate the KISS (Keep It Short and Simple) and YAGNI (You Ain't Gonna Need It) principles.

Personally, I prefer simple and effective solutions. I mostly use the "new" operator to instantiate stateful dependencies whenever and wherever they are needed. It is simple, well encapsulated, easy to understand, and easy to test. So, why not?

Rogerio
A: 

I belive in simplicity. Applying IOC/Dependecy Injection in Domain classes does not make any improvement except making the code much more harder to main by having an external xml files describing the relation. Many technologies like EJB 1.0/2.0 & struts 1.1 are reversing back by reducing the stuff the put in XML and try put them in code as annoation etc. So applying IOC for all the classes you develope will make the code non-sense.

IOC has it benefits when the dependent object is not ready for creation at compile time. This can happend in most of the infrasture abstract level architecture components, trying establish a common base framework which may need to work for different scenarios. In those places usage IOC makes more sense. Still this does not make the code more simple / maintainable.

As all the other technologies, this too has PROs & CONs. My worry is, we implement latest technologies in all the places irrespective of their best context usage.

Senthil Kumar Vaithilingam
+7  A: 

There is another way of looking at this issue that you might find interesting.

When we use IoC/dependency injection, we're not using OOP concepts. Admittedly we're using an OO language as the 'host', but the ideas behind IoC come from component-oriented software engineering, not OO.

Component software is all about managing dependencies - an example in common use is .NET's Assembly mechanism. Each assembly publishes the list of assemblies that it references, and this makes it much easier to pull together (and validate) the pieces needed for a running application.

By applying similar techniques in our OO programs via IoC, we aim to make programs easier to configure and maintain. Publishing dependencies (as constructor parameters or whatever) is a key part of this. Encapsulation doesn't really apply, as in the component/service oriented world, there is no 'implementation type' for details to leak from.

Unfortunately our languages don't currently segregate the fine-grained, object-oriented concepts from the coarser-grained component-oriented ones, so this is a distinction that you have to hold in your mind only :)

Nicholas Blumhardt
Positively great answer!
macke
+1  A: 

Pure encapsulation is an ideal that can never be achieved. If all dependencies were hidden then you wouldn't have the need for DI at all. Think about it this way, if you truly have private values that can be internalized within the object, say for instance the integer value of the speed of a car object, then you have no external dependency and no need to invert or inject that dependency. These sorts of internal state values that are operated on purely by private functions are what you want to encapsulate always.

But if you're building a car that wants a certain kind of engine object then you have an external dependency. You can either instantiate that engine -- for instance new GMOverHeadCamEngine() -- internally within the car object's constructor, preserving encapsulation but creating a much more insidious coupling to a concrete class GMOverHeadCamEngine, or you can inject it, allowing your Car object to operate agnostically (and much more robustly) on for example an interface IEngine without the concrete dependency. Whether you use an IOC container or simple DI to achieve this is not the point -- the point is that you've got a Car that can use many kinds of engines without being coupled to any of them, thus making your codebase more flexible and less prone to side effects.

DI is not a violation of encapsulation, it is a way of minimizing the coupling when encapsulation is necessarily broken as a matter of course within virtually every OOP project. Injecting a dependency into an interface externally minimizes coupling side effects and allows your classes to remain agnostic about implementation.

Dave Sims
+1  A: 

It depends on whether the dependency is really an implementation detail or something that the client would want/need to know about in some way or another. One thing that is relevant is what level of abstraction the class is targeting. Here are some examples:

If you have a method that uses caching under the hood to speed up calls, then the cache object should be a Singleton or something and should not be injected. The fact that the cache is being used at all is an implementation detail that the clients of your class should not have to care about.

If your class needs to output streams of data, it probably makes sense to inject the output stream so that the class can easily output the results to an array, a file, or wherever else someone else might want to send the data.

For a gray area, let's say you have a class that does some monte carlo simulation. It needs a source of randomness. On the one hand, the fact that it needs this is an implementation detail in that the client really doesn't care exactly where the randomness comes from. On the other hand, since real-world random number generators make tradeoffs between degree of randomness, speed, etc. that the client may want to control, and the client may want to control seeding to get repeatable behavior, injection may make sense. In this case, I'd suggest offering a way of creating the class without specifying a random number generator, and use a thread-local Singleton as the default. If/when the need for finer control arises, provide another constructor that allows for a source of randomness to be injected.

dsimcha
A: 

This is similar to the upvoted answer but I want to think out loud - perhaps others see things this way as well.

  • Classical OO uses constructors to define the public "initialization" contract for consumers of the class (hiding ALL implementation details; aka encapsulation). This contract can ensure that after instantiation you have a ready-to-use object (i.e. no additional initialization steps to be remembered (er, forgotten) by the user).

  • (constructor) DI undeniably breaks encapsulation by bleeding implemenation detail through this public constructor interface. As long as we still consider the public constructor responsible for defining the initialization contract for users, we have created a horrible violation of encapsulation.

Theoretical Example:

Class Foo has 4 methods and needs an integer for initialization, so its constructor looks like Foo(int size) and it's immediately clear to users of class Foo that they must provide a size at instantiation in order for Foo to work.

Say this particular implementation of Foo may also need a IWidget to do its job. Constructor injection of this dependency would have us create a constructor like Foo(int size, IWidget widget)

What irks me about this is now we have a constructor that's blending initialization data with dependencies - one input is of interest to the user of the class (size), the other is an internal dependency that only serves to confuse the user and is an implementation detail (widget).

The size parameter is NOT a dependency - it's simple a per-instance initialization value. IoC is dandy for external dependencies (like widget) but not for internal state initialization.

Even worse, what if the Widget is only necessary for 2 of the 4 methods on this class; I may be incurring instantiation overhead for Widget even though it may not be used!

How to compromise/reconcile this?

One approach is to switch exclusively to interfaces to define the operation contract; and abolish the use of constructors by users. To be consistent, all objects would have to be accessed through interfaces only, and instantiated only through some form of resolver (like an IOC/DI container). Only the container gets to instantiate things.

That takes care of the Widget dependency, but how do we initialize "size" without resorting to a separate initialization method on the Foo interface? Using this solution, we lost the ability to ensure that an instance of Foo is fully initialized by the time you get the instance. Bummer, because I really like the idea and simplicity of constructor injection.

How do I achieve guaranteed initialization in this DI world, when initialization is MORE than ONLY external dependencies?

Update: I just noticed Unity 2.0 supports providing values for constructor parameters (such as state initializers), while still using normal mechanism for IoC of dependencies during resolve().Perhaps other containers also support this? That solves the technical difficulty of mixing state init and DI in one constructor, but it still violates encapsulation!
urig
+3  A: 

This exposes the dependency being injected and violates the OOP principle of encapsulation.

Well, frankly speaking, everything violates encapsulation. :) It's a kind of a tender principle that must be treated well.

So, what violates encapsulation?

Inheritance does.

"Because inheritance exposes a subclass to details of its parent's implementation, it's often said that 'inheritance breaks encapsulation'". (Gang of Four 1995:19)

Aspect-oriented programming does. For example, you register onMethodCall() callback and that gives you a great opportunity to inject code to the normal method evaluation, adding strange side-effects etc.

Friend declaration in C++ does.

Class extention in Ruby does. Just redefine a string method somewhere after a string class was fully defined.

Well, a lot of stuff does.

Encapsulation is a good and important principle. But not the only one.

switch (principle)
{
      case encapsulation:
           if (there_is_a_reason)
      break!
}
topright
+3  A: 

As Jeff Sternal pointed out in a comment to the question, the answer is entirely dependent on how you define encapsulation.

There seem to be two main camps of what encapsulation means:

  1. Everything related to the object is a method on an object. So, a File object may have methods to Save, Print, Display, ModifyText, etc.
  2. An object is its own little world, and does not depend on outside behavior.

These two definitions are in direct contradiction to each other. If a File object can print itself, it will depend heavily on the printer's behavior. On the other hand, if it merely knows about something that can print for it (an IFilePrinter or some such interface), then the File object doesn't have to know anything about printing, and so working with it will bring less dependencies into the object.

So, dependency injection will break encapsulation if you use the first definition. But, frankly I don't know if I like the first definition - it clearly doesn't scale (if it did, MS Word would be one big class).

On the other hand, dependency injection is nearly mandatory if you're using the second definition of encapsulation.

kyoryu
I definitely agree with you about the first definition. It also violates SoC which is arguably one of the cardinal sins of programming and probably one of the reasons it doesn't scale.
macke
+1  A: 

PS. By providing Dependency Injection you do not necessarily break Encapsulation. Example:

obj.inject_dependency(  factory.get_instance_of_unknown_class(x)  );

Client code does not know implementation details still.

topright
A: 

Maybe this is a naive way of thinking about it, but what is the difference between a constructor that takes in an integer parameter and a constructor that takes in a service as a parameter? Does this mean that defining an integer outside the new object and feeding it into the object breaks encapsulation? If the service is only used within the new object, I don't see how that would break encapsulation.

Also, by using some sort of autowiring feature (Autofac for C#, for example), it makes the code extremely clean. By building extension methods for the Autofac builder, I was able to cut out a LOT of DI configuration code that I would have had to maintain over time as the list of dependencies grew.

blooware
A: 

I agree that taken to an extreme, DI can violate encapsulation. Usually DI exposes dependencies which were never truly encapsulated. Here's a simplified example borrowed from Miško Hevery's Singletons are Pathological Liars:

You start with a CreditCard test and write a simple unit test.

@Test
public void creditCard_Charge()
{
    CreditCard c = new CreditCard("1234 5678 9012 3456", 5, 2008);
    c.charge(100);
}

Next month you get a bill for $100. Why did you get charged? The unit test affected a production database. Internally, CreditCard calls Database.getInstance(). Refactoring CreditCard so that it takes a DatabaseInterface in its constructor exposes the fact that there's dependency. But I would argue that the dependency was never encapsulated to begin with since the CreditCard class causes externally visible side effects. If you want to test CreditCard without refactoring, you can certainly observe the dependency.

@Before
public void setUp()
{
    Database.setInstance(new MockDatabase());
}

@After
public void tearDown()
{
    Database.resetInstance();
}

I don't think it's worth worrying whether exposing the Database as a dependency reduces encapsulation, because it's a good design. Not all DI decisions will be so straight forward. However, none of the other answers show a counter example.

Craig P. Motlin
Unit tests are usually written by the class author, so it's ok to spell out the dependencies in the test case, from a technical point of view. When later credit card class changes to use a Web API such as PayPal, the user would need to change everything if it was DIed. Unit testing are usually done with intimate knowledge of the subject being tested (isn't that the whole point?) so I think tests are more of an exception than a typical example.
kizzx2
The point of DI is to avoid the changes you described. If you switched from a Web API to PayPal, you wouldn't change most tests because they'd use a MockPaymentService and CreditCard would get constructed with a PaymentService. You'd have just a handful of tests looking at the real interaction between CreditCard and a real PaymentService, so future changes are very isolated. The benefits are even greater for deeper dependency graphs (such as a class that depends on CreditCard).
Craig P. Motlin
@Craig p. Motlin How can the `CreditCard` object change from a WebAPI to PayPal, without anything external to the class having to change?
Ian Boyd
@Ian I mentioned CreditCard should be refactored to take a DatabaseInterface in its constructor which shields it from changes in the implementations of DatabaseInterfaces. Maybe that needs to be even more generic, and take a StorageInterface of which WebAPI could be another implementation. PayPal is at the wrong level though, because it's an alternative to CreditCard. Both PayPal and CreditCard could implement PaymentInterface to shield other parts of the application from outside this example.
Craig P. Motlin
@kizzx2 In other words, it's nonsense to say a credit card should use PayPal. They are alternatives in real life.
Craig P. Motlin
@Craig Maybe our semantics got a little confused. The main thing is that if you DI and you want to change your internal implementation, it's less transparent and violates encapsulation (as the question title). If you didn't use DI, nobody knows you have changed your internal implementation, so you're encapsulated. Consider this: If all your dependencies are DI'ed, you must rely on very generic interfaces and you must not downcast (because you don't know the concrete class supplied by your client). This works out in very pure scenarios but gets quite inflexible and limiting in real world, IMO.
kizzx2
@kizzx2 If you wanted to change CreditCard to persist somewhere other than a database, and if you're doing DI right, there should be exactly one place in your program where the text needs to change. You don't even need a container to achieve that, you can do it by hand. If the user really needs to change everything then either the DI pattern wasn't applied properly, or my original point is even more pronounced, that usually DI exposes dependencies which were never truly encapsulated.
Craig P. Motlin
@Craig the point was that DI does in some instance sacrifice encapsulation, as mentioned in your original answer. Anyway, my original comment was mainly about test case being a non representative example for the reason I stated.
kizzx2
@kizzx2 The test case only needs to be refactored if you are not using DI. It is meant to demonstrate that the dependency on the Database was never encapsulated at all, and after moving to DI, it's at least encapsulated behind an interface.
Craig P. Motlin