Dependency injection
- Dart course
- Expert
- Lesson 34/47
- 5 min
Learn dependency injection.
Dependency injection
Dependency injection (DI) means an object receives its dependencies from outside instead of creating them. They are injected via the constructor; this makes testing and swapping easier.
Example: class OrderService { final PaymentService payment; OrderService(this.payment); }. OrderService does not create PaymentService itself; it receives it. In tests a fake service is provided.
With DI you depend on an interface, not a concrete class. PaymentService interface can take StripePayment or PaypalPayment; OrderService does not care.
The DI container
A Container registers and resolves dependencies. container.register('math', MathService()) registers; container.resolve<MathService>('math') resolves.
The container also manages lifetime: a new instance per call (transient) or a single instance (singleton). This collects object creation logic in one place.
In large apps the container registers all dependencies at startup. At runtime only resolve is called; creation details stay hidden.
Practice Define PaymentService and OrderService
Define an abstract class PaymentService with bool pay(int amount);. Define a class StripePayment implements PaymentService with @override bool pay(int amount) => true;. Define a class OrderService with final PaymentService payment; OrderService(this.payment); String checkout(int amount) { final ok = payment.pay(amount); return ok ? 'paid: $amount' : 'failed'; }. In main create final order = OrderService(StripePayment()); and add print(order.checkout(100));.
Starter code
void main() {
// define an abstract PaymentService (pay method)
// define a StripePayment (applies the interface)
// define an OrderService class (payment field, checkout method)
// create an OrderService; print checkout(100)
}Sample solution
abstract class PaymentService {
bool pay(int amount);
}
class StripePayment implements PaymentService {
@override
bool pay(int amount) => true;
}
class OrderService {
final PaymentService payment;
OrderService(this.payment);
String checkout(int amount) {
final ok = payment.pay(amount);
return ok ? 'paid: $amount' : 'failed';
}
}
void main() {
final order = OrderService(StripePayment());
print(order.checkout(100));
}Expected output
paid: 100
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What does dependency injection make easier?
- UI drawing
- File reading
- Testing and swapping Correct answer
- Network listening
Explanation: DI makes providing fake dependencies in tests and swapping easier.
2 Match the DI parts
| Term | Meaning |
|---|---|
constructor |
Injection point |
inject |
Provide dependency |
Container |
Provider |
resolve |
Resolve |
3 Constructor injection
class OrderService {
final ____ payment;
OrderService(this.payment);
}
class OrderService {
final PaymentService payment;
OrderService(this.payment);
}
Explanation: the dependency is declared with its interface type.