Sparround

Dependency injection

Dependency injection in one sentence: an object does not create its dependencies, it receives them.

``` // no: the class wires itself to the network class OrderRepo { final api = ApiClient(); }

// yes: the dependency is supplied class OrderRepo { OrderRepo(this.api); final ApiClient api; } ```

The difference shows up in tests: the first version cannot be tested without a real network; the second only needs a fake ApiClient.

Three approaches are common in Flutter: the constructor (simplest), `InheritedWidget`/Provider (through the tree), and a service locator (get_it — a global registry).

ApproachStrengthWeakness
ConstructorExplicit — dependencies are visible in the signatureThreading it through a deep tree is tedious
Provider / RiverpodReaches down the tree, lifetime managedRequires a `BuildContext`
Service locator (`get_it`)No context needed, reachable anywhereDependencies are hidden — the signature does not reveal them

Interview tip. The service-locator question can be a trap: get_it is convenient but it hides dependencies — you cannot tell from a class's signature what it needs, which surfaces later as a forgotten mock in a test. A strong answer: I use constructor injection in business classes and keep get_it for the composition root, where objects are wired together, or for places with no context.

📚 Sources and documentation