Dependency injection supplies a class’s collaborators from outside, usually through its constructor, instead of letting the class instantiate them directly. Its immediate payoff is visible dependencies: a reader can see what a class needs at the point it is created. section 4.4 section 2.1.5
Use it to keep responsibilities narrow and replaceable. An import service can receive an EmployeeRepository and EmployeeImportCSVParser, then focus on coordinating imports rather than configuring parsing. A bot adapter can receive its SDK client instead of constructing one while sending a message. section 2.1.5 section 4.2.2
Constructor injection
A class that accepts a parser and repository can parse input, find an employee, and choose create or update behavior without owning parser construction. Passing alternative implementations at runtime lets the same class work with different bots or user directories; mocks can replace costly or external collaborators in isolated tests. section 2.1.5 section 4.4
Injection does not eliminate coupling; it makes coupling easier to locate and control. Static calls can hide dependencies throughout a class, while constructor parameters expose them. Performance objections are usually not decisive outside exceptionally large-scale systems, but the technique should not become an excuse for an unnecessarily complex graph. section 4.4 section 4.4.3
Inspect the MessageSender dependency graph to see how constructor-injected collaborators require their own dependencies and form a larger object graph. section 4.4.4
For deep graphs, dependency injection frameworks such as Spring or Guice can construct collaborators automatically. For straightforward applications, especially small command-line tools, factory classes may be a simpler choice. Choose the approach whose downsides remain controlled. section 4.4.3




















