Dependency Injection is a practice where objects are designed in a manner where they receive instances of the objects from other pieces of code, instead of constructing them internally. This means that any object implementing the interface which is required by the object can be substituted in without changing the code, which simplifies testing, and improves decoupling.
For example, consider these clases:
public class PersonService {
public void addManager( Person employee, Person newManager ) { ... }
public void removeManager( Person employee, Person oldManager ) { ... }
public Group getGroupByManager( Person manager ) { ... }
}
public class GroupMembershipService() {
public void addPersonToGroup( Person person, Group group ) { ... }
public void removePersonFromGroup( Person person, Group group ) { ... }
}
In this example, the implementation of PersonService::addManager
and PersonService::removeManager
would need an instance of the GroupMembershipService in order to do its work. Without Dependency Injection, the traditional way of doing this would be to instantiate a new GroupMembershipService
in the constructor of PersonService
and use that instance attribute in both functions. However, if the constructor of GroupMembershipService
has multiple things it requires, or worse yet, there are some initialization "setters" that need to be called on the GroupMembershipService
, the code grows rather quickly, and the PersonService
now depends not only on the GroupMembershipService
but also everything else that GroupMembershipService
depends on. Furthermore, the linkage to GroupMembershipService
is hardcoded into the PersonService
which means that you can't "dummy up" a GroupMembershipService
for testing purposes, or to use a strategy pattern in different parts of your application.
With Dependency Injection, instead of instantiating the GroupMembershipService
within your PersonService
, you'd either pass it in to the PersonService
constructor, or else add a Property (getter and setter) to set a local instance of it. This means that your PersonService
no longer has to worry about how to create a GroupMembershipService
, it just accepts the ones it's given, and works with them. This also means that anything which is a subclass of GroupMembershipService
, or implements the GroupMembershipService
interface can be "injected" into the PersonService
, and the PersonService
doesn't need to know about the change.