As my interest grows to learn more about the J2EE development platform (I strongly believe that knowledge of both platforms is needed to work in an IT architect role) I started looking at Spring.Net. Spring is the most widely used application framework in the Java world. Spring is somehow comparable to what the Microsoft Enterprise Library is offering. (Hmm, not exactly ...)
Spring (and also Spring.net) supports the Inversion of Control (IoC) principle in a really easy and efficient way. Not as complex as ObjectBuilder in Enterprise Library.
I came up with a little tutorial on Loose Coupling and Dependency Injection with Spring.NET. Design patterns like these are hard to understand without a good example. In this post I will guide you in this area by coding a simple scenario.
Let's consider a program which instantiates an object of ClassA (could be a windows form). That object needs a reference to another object that performs some logic (could be a domain object or a proxy to a WCF service). Let's call this ClassB. ClassA has a property which refers to ClassB. When the progam asks ClassA to do something, ClassA will call a method on ClassB.
Loose Coupling ? Loose Coupling comes in very handy for testing purposes : to test the behavior of ClassA we want to change ClassB to another Class (let's call it ClassB2) which has the same method but doesn't execute the logic to really call to a database backend but returns some hardcoded values. In a unit test we could assert the outcoming of the method in ClassA based on those harcoded values.
I will give you three different approaches for this scenario :
1. Not Loose coupled example, no dependency injection, no spring.net
class ClassA
{
public ClassB refToB { get; set; }
public void DoSomething()
{
string answerFromDatabase;
answerFromDatabase = refToB.GetSomehingFromADatabase();
Console.WriteLine(answerFromDatabase);
}
}
There's is no way to use another version of ClassB (ClassB2) without changing ClassA and recompiling it. ClassA is really dependent on ClassB.
So this code snippet will not compile.
a = new ClassA();
a.refToB = new ClassB();
a.DoSomething();
a.refToB = new ClassB2(); //<- does not compile of course.
a.DoSomething();
A solution for this is working with interfaces.
2. Loose Coupled with an Interface, no dependency injection, no spring.net
An Interface called IClassB is added.
public interface IClassB
{
String GetSomethingFromADatabase();
}
Now both ClassB and ClassB2 implement this interface. This interface holds the definition of the methods that ClassB (and ClassB2) should implement. ClassA now has a property which type is this Interface.
class ClassA
{
public IClassB refToB { get; set; }
public void DoSomething()
{
string answerFromDatabase;
answerFromDatabase = refToB.GetSomethingFromADatabase();
Console.WriteLine(answerFromDatabase);
}
}
This allows the calling code to decide which version of ClassB is given to ClassA. Both code snippets below are correct.
a = new ClassA();
a.refToB = new ClassB();
a.DoSomething();
a.refToB = new ClassB2();
a.DoSomething();
OK, more or less loose coupled, ... but again we need to recompile the application to switch from the real ClassB to the hardcoded ClassB2.
3. With Dependeny Injection using Spring.NET
Instead of using a property we add a constructor to ClassA which takes a reference to the interface IClassB as paramater. This construcor will hold this reference in a private field inside the class. The type of this private field is also the interface.
class ClassA
{
private IClassB refToB;
public ClassA(IClassB b)
{
refToB = b;
}
public void DoSomething()
{
string answerFromDatabase;
answerFromDatabase = refToB.GetSomethingFromADatabase();
Console.WriteLine(answerFromDatabase);
}
}
By using the IoC container of Spring.NET the choice of which version of the class (ClassB or ClassB2) to be used by ClassA is defined in the app.config file and the instantiation of ClassA is done by calling the static method GetObject() on the Spring context with a string as parameter that refers to the needed object (ClassB or ClassB2) in the spring section of the configuration.
a = (ClassA)ContextRegistry.GetContext().GetObject("MyClassA");
a.DoSomething();
Notice that the new statement is not used anymore, which is typicall when using the Inversion of Control pattern.
The dependencies between ClassA and an implementation of ClassB is defined in the spring section of the app.config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net" >
<object id="MyClassA"
type="SimpleSpringDemo.WithDI.ClassA, SimpleSpringDemo"
singleton="true">
<constructor-arg index="0" ref="MyClassB"/>
</object>
<object id="MyClassB"
type="SimpleSpringDemo.WithDI.ClassB, SimpleSpringDemo"
singleton="true">
</object>
</objects>
</spring>
</configuration>
In this configuration the object with id MyClassA will be instatiated as singleton (as defined by setting the singleton attribute to "true") and Spring injects the object refered by MyClassB into the constructor. MyClassB refers to the type (defined by a namespace, classname an assemblyname) of the actual object the IOC container will instantiate and give to ClassA as the parameter in the constructor.
So without recompiling, by just changing the configuration, we can decide wich object classA will use to perform it's tasks : the real object talking to the backend or a harcoded mock object.
Great !!