Since starting to practise proper TDD, I started to learn dependency injection too. It's a simple pattern that makes a world of difference. The following are some resources which I found helpful when getting to grips with it:
class ShoppingCartItem
{
private ILogger logger;
private string name;
public ShoppingCartItem(ILogger logger, string name)
{
this.logger = logger;
this.name = name;
}
}
class ShoppingCart
{
private IKernel kernel;
public ShoppingCart(IKernel kernel)
{
this.kernel = kernel;
}
public void AddItem(string name)
{
ShoppingCartItem item = kernel.Get<ShoppingCartItem>(
new ConstructorArgument("name", name));
...
}
}This works, but it is wrong! Ninject will self-inject the kernel to the ShoppingCart, and then inject the ILogger to the ShoppingCartItem. But this is bad for a couple of reasons:
class ShoppingCartItemFactory
{
private ILogger logger;
public ShoppingCartItemFactory(ILogger logger)
{
this.logger = logger;
}
public void CreateItem(string name)
{
return new ShoppingCartItem(logger, name);
}
}
class ShoppingCart
{
public ShoppingCart(ShoppingCartItemFactory itemFactory)
{
this.itemFactory = itemFactory;
}
public void AddItem(string name)
{
ShoppingCartItem item = itemFactory.CreateItem(name);
...
}
}Now everything is decoupled, the syntax is clean, and we still have the ability to inject mock items by injecting a different factory implementation.