28 March, 2008

simple dependency injection

the idea behind dependency injection has been around for a while, and i believe the term "poor man's dependency injection" is popular as well, but i thought i'd share the poor man's method anyhow.

it's common to find that n-tiered applications (especially applications with a persistence layer and a "business logic layer") although layered, are usually tightly coupled.

one nuisance that this coupling creates is the inability to write unit tests that only test the business layer. even though you can write tests for the business layer, these cannot run without calling the persistence layer, and thus you end up with slow tests (because of db calls) and redundant tests (assuming you have tests for your persistence layer).

a very simple method (the poor man's method, of course) to solve this coupling problem is to:

  1. code to an interface (in the case of the service layer, make sure you're not calling a specific implementation of your persistence layer, but an interface).
  2. overload the constructor(s) for your business logic class so that they also take a specific implementation of the interfaces it depends on.
if you do what i've described above, your business layer should end up looking something like this:

public interface IPersistenceLayer
void DoWork();

public class BusinessLogicLayer
IPersitenceLayer myDataStore;
public BusinessLogicLayer(IPersistenceLayer someImplementation)
myDataStore = someImplementation;

public void DoWork()
//business logic here

with the above code you can easily write tests for your business layer that just take a dummy IPersistenceLayer and return mock objects. and so now we have fast tests that don't require any database setup and/or maintenance.

there is however, one obvious problem with the code presented: why should the clients to the business layer have to know about the layer's dependency? the answer is they shouldn't and that's why we keep all the default constructors, and just have those set the IPersistenceLayer reference to the commonly use implementation of the interface.

although almost trivial, this method of dependency injection is appropriate for simple scenarios and provides much flexibility.