Design Patterns interview question · Most asked

What is dependency injection, and what forms does it take?

Summary

Dependency injection means an object receives its collaborators from outside instead of creating them. The forms are constructor injection (the default), setter or property injection (optional or changeable dependencies) and method injection (one call needs it).

Longer Answer

DI makes dependencies explicit and swappable: tests pass fakes (an in-memory mailer, a fixed clock), and production wires real implementations in one composition root. Frameworks like Spring, Laravel's container, NestJS and FastAPI's Depends automate the wiring.

Inject things that do I/O, hold state or need faking: databases, HTTP clients, clocks, random numbers. Ten constructor parameters signal an SRP problem, not a DI problem.

Code Example

class FixedClock:
    def today(self):
        return "2030-01-01"


class Signup:
    def __init__(self, clock):  # constructor injection
        self.clock = clock

    def welcome(self, email):
        return f"{email} joined on {self.clock.today()}"


print(Signup(FixedClock()).welcome("[email protected]"))

Key Points

  • Pass dependencies in.
  • Constructor injection is the default.
  • Composition root wires real objects.
  • Too many dependencies = too many responsibilities.

Deep dive: Design Patterns, Explained Simply: Dependency Injection Without a Framework

Explanation

What interviewers look for

Constructor injection as default, testability benefits, and knowing DI works without a container.

Follow-up questions

  • What is a composition root?
  • How does Spring or Laravel resolve dependencies automatically?

More most-asked Design Patterns questions

← All Design Patterns questions