The Dependency Injection pattern suggests that a class should not directly instanciate it’s dependencies but, instead, should provide a way for the dependencies to be “injected” - usually as constructor parameters.
Without dependency injection
public class UserService
{
private readonly UserRepository _userRepository;
public UserService(string connectionString, CachingOptions cachingOptions)
{
_userRepository = new UserRepository(connectionString, cachingOptions);
}
}
Refactored to use dependency injection
public class UserService
{
private readonly UserRepository _userRepository;
public UserService(UserRepository userRepository)
{
_userRepository = userRepository;
}
}
Notice how after the refactoring, UserService
class does need to know how create a UserRepository
but only how to use it. This reduces coupling and is a step towards Single Responsibility design pattern.
There is another refactoring that we can make that although is not strictly part of Dependency Injection (but more part of Dependency Inversion) it allows for much greater flexibility and decoupling.
Refactored to use Dependency Inversion
public interface IUserRepository
{
...
}
public class UserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
}
After this second refactoring, the UserService
does not depend on the concrete implementation of the UserRepository
but on the interface IUserRepository
and this makes it much more easier to mock the UserRepository
for unit testing.
public class TestUserRepository: IUserRepository
{
public User[] GetUsers
{
return new [] {new User (...), new User(...)};
}
}
public class UserServiceTests
{
public void Test()
{
var service = new UserService(new TestUserRepository)
Assert(2, servive.GetAllUsers().Length);
}
}