According to Why should I use dependency injection?, “dependency injection” has some advantages, for example:
“Non dependency injection” version:
public class Client{
private Logger logger;
public Client(){
this.logger=new Logger();
}
}
“Dependency Injection” version:
public Interface ILogger{
}
public class Client{
private ILogger logger;
public Client(ILogger logger){
this.logger=logger;
}
}
Dependency Injection version is better because:
-
Client doesn’t need to always depend on Logger, which can use other types of ILogger (eg:PrinterLogger) instead of bind to specific implementation
-
Easier to test : Dependency Injection version don’t need to new a Logger object first to test Client, or we may replace Logger to other ILogger such as PrinterLogger, more likely a unit test instead of integration test
-
Looser coupling : Removing Logger class doesn’t require me to modify Client to recompile
-
More reuseable Client : I don’t need to create another Client or another constructor when I need another Logger, eg: I don’t need to add : public Client(){ this.logger=new PrinterLogger(); } when I want to use PrinterLogger
And when there are some codes “pass required parameters only”, for example:
“Pass required parameters only” version:
public class showInfo(String name, int age){
}
this.showInfo(student.getName(),student.getAge());
it would usually be considered as code smell and want to be refactored as “preserve whole object”:
“Preserve whole object” version:
public void showInfo(Student student){
}
this.showInfo(student);
However, I think change “Preserve whole object version” to “pass required parameters only” seems go the similar direction of “dependency injection” and have similar advantages:
-
showInfo() doesn’t need to depend on Student, which can use other types of objects that also contain name and age (eg: Teacher) instead of binding specific implementation
-
Easer to test : Pass required parameters only don’t need to new a Student object first to test showInfo(),or we may replace Student with other objects that also has name and age such as Teacher at the calling client side, more likely a unit test instead of integration test
-
Looser coupling : Removing Student class doesn’t require me to modify showInfo() to recompile
-
More reuseable showInfo() : I don’t need to create another showInfo() method when I need another object (eg: I don’t need to add public void showInfo(Teacher teacher){} when I want to show info of Teacher that also contains name and age)
Also I think I can apply the advantages of “Preserve whole object” to say “Non dependency injection” is better:
-
“Non dependency injection” has less parameters in the Client constructor, which fits the motivation of “Preserve whole object” that shorter parameter list is better
-
In “Non dependency injection”, adding new components don’t need to modify the parameter list of constructors,eg:
public class Client{
private Logger logger;
private Timer timer;
public Client(){
this.logger=new Logger();
this.timer=new Timer();
}
}
but the “Dependency injection” version needs to add a new parameter:
public class Client{
private ILogger logger;
private Timer timer;
public Client(ILogger logger, ITimer timer){
this.logger=logger;
this.timer=timer;
}
}
- “Non dependency injection” types less words when calling constructors:
Client c1=new Client();
Client c2=new Client();
instead of
Client c1=new Client(new Logger());
Client c2=new Client(new Logger());
, as if in showInfo() repeating getters:
showInfo(student);
instead of
showInfo(student.getName(),student.getAge());
But I guess you would not say “Dependency injection” is code smell, and should be refactored to “Non dependency injection” version, right?
But I believe the fact is, “Pass required parameters only” is always considered a code smell waiting to be refactored as “Preserve whole object”, instead of some code smell that waiting to be refactored to “Pass required parameters only”.
So my question is, why is “Dependency Injection” ok, but not “Pass required parameters only” even if I think they are having similar goals and going to similar directions?