Sunday, December 14, 2008

IoC and Dependecy Injection

IoC (Inversion Of Control) is one of many programming concepts that when I was first approached with it I wondered why on earth anyone would have need of such and thing and now I can't imagine a world without it.

The 10,000 foot simple view of it goes something like this:
  1. Anything in your code that requires a resource or code from somewhere else is a "dependency". Examples: database access, another class that provides a method call or service,a web service, etc, etc.
  2. Give all your dependencies an interface or an abstract underclass. have all of your code depend on these instead.
  3. Make all your dependencies come into your class via the constructor, a method parameter, or a setter property. Your end goal is to never have "new" called on anything unless you're working with a class that only contains data . Also using static methods to get around new is cheating and still hard coding a dependency.
  4. Use a third party solution or wire up your own IoC container, that looks at all your dependencies and plays match maker (oh this class needs widget a,b, and c , let me call new widget a, b,c, and add them to this class when called). This replaces all your "Factory" style classes.
Short example of this in code is as follows:

public interface DrawWidget{

void Draw();
}

public class ColorWidget: DrawWidget
{
public ColorWidget()
{
//imagine this connects and initializes connection to printer

}
public void Draw()
{

// imagine color widget active code here

}
public interface WidgetData
{

public string[] GetStrings();
}
public class WidgetDb : WidgetData
{
public WidgetDB()
{
// imagine this sets up connections strings and makes db connection.

}
public string[] GetStrings()
{
//imagine db code here
}

}



traditional approach:


public class WidgetCombiner
{

public CombinedWidget WidgetPayload()

{

WidgetPayLoad payload = new WidgetPayload();
payload.Draw = new ColorWidget();//connection to printer must be alive
payload.Data = new WidgetDb(); //connection to db must be alive

return payload;



}

}



Dependency Injection Approach

public class WidgetCombiner{

private DrawWidget draw;
private WidgetData data;

public WidgetCombiner( DrawWidget draw, WidgetData data)
{
this.draw = draw;
this.data = data;
}

public CombinedWidget WidgetPayload()

{
WidgetPayLoad payload = new WidgetPayload();
payload.Draw = this.draw;
payload.Data = this.data;

return payload;
}




The key difference is WidgetCombiner in the first "traditional" implementation it depends on the printer being live and the database connection functioning. The second implementation does not care at all, it's dependency is dynamic and easily changed to another database, another printer, or just a fake test environment.

No comments: