Thursday, September 06, 2007 11:37 AM
Not many people would argue the value of
dependency injection, especially when it comes to replacing a live object with a faked object for testing. Although most implementations of this take advantage injecting the faked object into the constructor of the consuming object at instantiation time, did you know that there's another way to easily swap objects in and out using generics?
Here's how...
Imagine you have a data access layer which depends on a valid database connection. You don't want to use a real database in testing do you? Of course not. So how do you handle the situation? You abstract the database connection out to an interface and provide a fake implementation of that same interface, often using
mock objects. Take the example below, here we have an IConnection interface which represents a data connection. However, we've implemented a FakeConnection class which simply contains an underlying list of Customers instead a live connection to an actual database. Using traditional dependency injection, we simply "inject" the fake implementation into the DataLayer's constructor at creation time. Since the FakeConnection also implements the IConnection interface the DataLayer doesn't know the difference...
/// <summary>
/// Initializes a new instance of the <see cref="DataLayer<T>"/> class.
/// </summary>
/// <param name="connection">The connection.</param>
public DataLayer(IConnection connection)
{
_connection = connection;
}
FakeConnection fakeConnection = new FakeConnection();
DataLayer dataLayer = new DataLayer(fakeConnection);
However, using generics and constraints, you can accomplish this same technique. Here is the declaration of the class that could accept an IConnection object as an interface...
/// <summary>
/// Represents a actual data layer.
/// </summary>
/// <typeparam name="T">The type of the connection to use.</typeparam>
public class DataLayer<T> where T : IConnection, new()
{
. . .
}
And here's how one would consume this class...
DataLayer<FakeConnection> dataLayer =
new DataLayer<FakeConnection>();
The difference lies in the fact that we don't have to explicitly create an instance of FakeConnection before passing it to the DataLayer. The DataLayer's constructor will create the instance for us automatically using the following code...
/// <summary>
/// Initializes a new instance of the <see cref="DataLayer{T}"/> class.
/// </summary>
public DataLayer()
{
_connection = (T)Activator.CreateInstance(typeof(T));
}
Note the use of the new() constraint in the signature of the DataLayer<T> class. This is a result of our dependence on the Activator class in the DataLayer's constructor above to create our instance of IConnection via reflection.
I've included the
source code of a small working project using this technique so you can get the full picture. However, I'll leave it as an exercise to the reader to determine if this technique is actually worthwhile. It could be argued that less code is required by the consumer class as the creation of the appropriate instance of IConnection is encapsulated in the DataLayer. However, this additional responsibility of the DataLayer could arguably be considered out of scope for the object and would definitely complicate the creation of an object with a valid connection string.
Let me know what you think. And if you're interested in more information, Michael Feathers discusses this technique briefly in his highly recommended book
Working Effectively with Legacy Code.