PDA

View Full Version : Dependency Injection, local variables, and design


Tom Whitner
10-20-2004, 05:01 PM
Throughout the process of learning about Dependency Injection and evaluting Spring.NET, I have encountered the statement that DI leads to better design. While I believe this to be generally true, I am not convinced that it is universally true. My specific concern here is that in order to use DI, the objects to be injected must be class member that can be set via ctor, property, or interface. Regardless, this seems to mandate that local variables, those with method scope, must be promoted to class scope in order to accomplish injection. For instance:

// Original Implementation
public class Foo {
public Foo() {
}
public void Bar() {
IDoSomethingUseful dsu = new DoSomethingUsefulImplementation();
dsu.AddValue();
}
}
// DI Implementation
public class Foo2 {
// note the increase in scope of this variable
private IDoSomethingUseful _dsu;
public Foo2(IDoSomethingUseful dsu) {
_dsu = dsu;
}
public void Bar() {
_dsu.AddValue();
}
}


Is this increase in scope desirable? Or is it simply an acceptable side-effect of using Dependency Injection?

Mark Pollack
10-20-2004, 07:24 PM
Hi,

If you would like to easily change which implementation of IDoSomethingUseful the Foo class is using, then making it a private data member is very valuable and do not see this as a bad thing. Although it depends on what IDoSomethingUseful is doing, you might not want it created over and over again for each method invocation anyway.

I would say the DI code you list is preferable, even if you don't use Spring's object factory, since it gives you the ability to change the implementation. With Spring's IoC container, switching just becomes a configuration change instead of a code change.

- Mark

Tom Whitner
10-20-2004, 08:51 PM
Ok, I agree the DI approach is better than the orignal approach because it allows for replacement of the implementation, but so does the following approach:

// Service Locator Implementation
public class Foo {
public Foo() {
}
public void Bar() {
IDoSomethingUseful dsu = Locator.GetObject("DoSomethingUsefulImplementation") as IDoSomethingUseful;
dsu.AddValue();
}
}

With this approach, we've allowed for replacement via the locator and kept the scope as we orignally intended it. Additionally, the locator can deal with issues such as singletons, etc. The only drawback I see is a dependecy on the locator itself.

Mark Pollack
10-20-2004, 11:38 PM
Hi,

Is introducing a dependency, especially if it is a 3rd party library, worse than making a local method variable a class private variable - yes. I never worried about that type of 'scope' issue before - what is the issue there? The locator approach is adding code to the business object that is not related to the business logic, so if you can get rid of it, why not - you will never miss it! You get a much cleaner implementation if you use IoC/Dependency injection. There isn't any factory/configuration code in your business object. Depending on how much information you are 'pulling' in from elsewhere, that can start to add up to a real amount of code cruft - parsing XML snips, getting values, using the Locator, setting them, etc. This can be avoided using an IoC approach.

If you still want to go down the route of using the Locator approach, you should consider using Spring's IObjectFactory or IApplicationContext as the "Locator". Implementing IObjectFactoryAware or IApplicationContextAware will give you a reference to these objects. Your business object is coupled to Spring but you get to use the full featured factory we provide - a logical name to what you are retrieving, setting properties of the created object, referencing of other objects, support for singleton/non-singleton and all the other goodies you can read about in the docs.

That being said, I feel the IoC approach is better, since you don't couple your class to any external locator API for object creation and configuration purposes.

- Mark

choyrim
10-22-2004, 04:14 AM
I think the key word here is "Universal." Information hiding is still a good thing. So exposing more than you need to is always something you need to look into.

It important to consider Spring to be yet another component model. And for these slightly bigger blocks, Microsoft and Java history have proven that the convenience of extra visibility is well worth the loss of information hiding. What kind of convenience does that visibility afford? Well, for one, rapid development seems to require a lot of visibility into your component state. The advantages of Spring (and other RAD things) depend on being able to manipulate that exposed state.

Another point I'd like to add is that, I think Spring brings scripting-like benefits for statically typed languages. Often you'd really like to use a dynamic scripting language to handle your static types. For flexibility and whatnot. Spring provides those features in a way that makes sense most of the time.

Not every object should be inside the Spring container. But those areas that could really benefit from the scripting-like dynamically bound approach to binding and configuring will really find a great home in Spring.NET.

--Choy

Rick Evans
10-22-2004, 09:13 AM
Hi

I'd also add that the DI approach is more amenable to (unit) testing. With the Service Locator approach, there is (obviously) a dependency on the ServiceLocator... this dependency has to be configured prior to executing the test of any class that has such a dependency.

With the DI approach, since the unit under test is a Plain Old .NET Object (PONO), the class under test only needs instances of whatever classes are actually used in the execution of any unit tests... there's no need to handle any configuration plumbing required by a ServiceLocator; one just plugs in some objects right there in the body of the unit test using plain vanilla property setters / ctor arguments and fires away... in the case of the example class described in the originating post, this would be an appropriate implementation of the IDoSomethingUseful interface.

Having said that, one might want these 'plugin' objects to be configured, and Spring.NET is great for actually getting a handle on these 'plugin' objects (if one wanted to go down this road)... one could pull them straight out of an appropriately configured IoC container, in effect using the Spring.NET IoC container as a glorified ServiceLocator. Simply setting properties / ctor args for one's PONO's is the best approach for unit testing though... configuration via an IoC container such as Spring.NET is better suited to integration testing.

Ciao
Rick