Why is "dependency injection" ok, but not "the opposite of preserve whole object (pass required parameters only)"?

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 doesn'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 instead of Logger. So on one hand, "dependency injection" has the advantages above. On the other hand, 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); Although "preserve whole object" seems considered as better style in many cases, however, I think the opposite refactoring : change "Preserve whole object" 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 Easier to test : Pass required parameters only doesn'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 information of Teacher that also contains name and age instead of Student). Although I can apply the advantages of "dependency injection" to "pass required parameters only", I believe the fact is, "Pass required parameters only" is often considered as a code smell waiting to be refactored to "Preserve whole object", instead of some other codes with 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? Also oppositely, 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 doesn't need to modify the parameter list in 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 to the constructor: public class Client{ private ILogger logger; private ITimer timer; public Client(ILogger logger, ITimer timer){ this.logger=logger; this.timer=timer; } } which "Non dependency injection" fits the situation of "preserve whole object is better" that passing "Studnet" instead of "name" and "age" allows us adding new properties (eg: dateOfBirth) without modify the parameter list "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 "preserve whole object" version that showInfo() types "student" only: showInfo(student); instead of typing getters at each parameter: showInfo(student.getName(),student.getAge()); But I guess you would not say "Dependency injection" is code smell because of violating the principle of "preserve whole object", and should be refactored to "Non dependency injection" version, right? So the qu

May 22, 2025 - 18:40
 0

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:

  1. Client doesn't need to always depend on Logger, which can use other types of ILogger (eg:PrinterLogger) instead of bind to specific implementation

  2. Easier to test : Dependency Injection version doesn'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

  3. Looser coupling : Removing Logger class doesn't require me to modify Client to recompile

  4. 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 instead of Logger.

So on one hand, "dependency injection" has the advantages above. On the other hand, 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);

Although "preserve whole object" seems considered as better style in many cases, however, I think the opposite refactoring : change "Preserve whole object" to "pass required parameters only", seems go the similar direction of "dependency injection" and have similar advantages:

  1. 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

  2. Easier to test : Pass required parameters only doesn'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

  3. Looser coupling : Removing Student class doesn't require me to modify showInfo() to recompile

  4. 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 information of Teacher that also contains name and age instead of Student).

Although I can apply the advantages of "dependency injection" to "pass required parameters only", I believe the fact is, "Pass required parameters only" is often considered as a code smell waiting to be refactored to "Preserve whole object", instead of some other codes with 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?

Also oppositely, I think I can apply the advantages of "Preserve whole object" to say "Non dependency injection" is better:

  1. "Non dependency injection" has less parameters in the Client constructor, which fits the motivation of "Preserve whole object" that shorter parameter list is better

  2. In "Non dependency injection", adding new components doesn't need to modify the parameter list in 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 to the constructor:

public class Client{
    private ILogger logger;
    private ITimer timer;
    public Client(ILogger logger, ITimer timer){
        this.logger=logger;
        this.timer=timer;
    }
}

which "Non dependency injection" fits the situation of "preserve whole object is better" that passing "Studnet" instead of "name" and "age" allows us adding new properties (eg: dateOfBirth) without modify the parameter list

  1. "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 "preserve whole object" version that showInfo() types "student" only:

showInfo(student);

instead of typing getters at each parameter:

showInfo(student.getName(),student.getAge());

But I guess you would not say "Dependency injection" is code smell because of violating the principle of "preserve whole object", and should be refactored to "Non dependency injection" version, right? So the question again : why can "dependency injection" ignore the issues that "preserve whole object" addresses?