I know some OOP and have read this and that, but am not a hardcore OOP guy and have no formal training and can't rattle off why something should use dependency injection or not, and may not be able to identify all dependencies in a design, hence my question.
Answering a question here on SO (Using a object in methods of other objects) I started to doubt myself. As far as dependencies, is one of these better or worse or both acceptable? Any design limitations?
I have read and understand both but haven't ever come across a comparison. Why would one be better used in a design, etc.
Dependency Injection:
class myClass {
private $db;
public function __construct($db) {
$this->db = $db;
}
}
Registry (maybe also something else):
class myClass {
private $db;
public function __construct() {
$this->db = Registry::get('db');
}
}
Both methods are possible implementations of dependency injection. Basically dependency injection means to define a way to configure (inject) the classes to be used at runtime in order to make to code more flexible compared to using using hard coded class names and constructors in the code. Dependency injection follows a principle called inversion of control
.
This is especially interesting for testing code but can be used in a variety of other scenarios where you want to make an application flexible and maintainable.
While dependency injection mostly is referred to as DI container
, it can generally be done using a couple of different methods - which may also coexist. Here comes an (incomplete) list:
- using a dependency injection container
- pass class dependency as constructor or method args
- using a central registry (as long as it is configurable)
- using setter methods to set dependencies
- using configuration files
- user input
- ...
It has a lot to do with testability.
In your example, the first (Dependency Injection) is better. The reason it's better is because it accepts db
as an argument, which means this is testable, you can use a mock db
for testing and test myClass
does the right thing with it.
The second example (Registry) is not recommended as not only myClass
depends on db
, it now also depends on Registry
, and the worst part it's that it knows how to get a db
. It's too smart, it should be dumb like the first one, dumb things are more testable, smart things are not.
A dependency injection is required because the object needs certain data to perform its functions correctly.
Dependency Injection can be performed in three different ways:
- If Object A depends on object B, then you can create object A while creating object B
- You can use some external class ( like Registry, configuration files etc ) to load the dependency objects, This will decouple the creation of your object from the dependency creation. This is called locator pattern where your object creation is dependent upon the locator to load the objects.
- You can create the dependency elsewhere and provide it directly to the dependent object. This is called 'manual injection'
Whenever you do any of these, you are already doing dependency injection:
Constructor injection
public class ClassA
{
// declares the dependency in the constructor
public function ClassA( dependency1:String )
{}
}
// and the dependency is created while instantiating the object
var objA:ClassA = new ClassA("Hello World");
Public property injection
public class ClassA
{
// declares the dependency as a public property
public var helloStr:String;
}
var obj1:ClassA = new ClassA();
// dependency is fulfilled by setting a public property after instantiation:
obj1.helloStr = "The Zen Master";