# Dependency Injection as a Pattern — Design Patterns

Source: https://www.skillbyai.com/en/design-patterns/c-di

> Pass dependencies in instead of reaching out for them.

## Inversion of control in practice

**Intent:** a component receives its collaborators from outside (usually through its constructor) instead of creating or looking them up itself. This applies the dependency inversion principle: `CheckoutService` depends on a `PaymentGateway` interface, and the composition root decides whether that is a real provider or a fake. Benefits: explicit dependencies, easy testing with fakes, and swapping implementations without editing the class. **Manual DI** (wiring with `new` in one startup file) is enough for many apps. **DI containers** automate the wiring and lifetimes (singleton, per-request, transient); examples include Spring in Java, the built-in container in ASP.NET Core, Angular's injector, and NestJS or InversifyJS in TypeScript. **Avoid** using a container as a *service locator* that classes call directly, which hides dependencies again.

## Constructor injection and a test fake

Manual DI with a composition root.

```typescript
interface PaymentGateway {
  charge(customerId: string, amountCents: number): Promise<{ ok: boolean; id?: string }>;
}

class CheckoutService {
  constructor(
    private payments: PaymentGateway,
    private orders: OrderRepository,
  ) {}

  async checkout(cart: Cart) {
    const result = await this.payments.charge(cart.customerId, cart.totalCents);
    if (!result.ok) throw new Error('Payment declined');
    return this.orders.create(cart, result.id!);
  }
}

// Composition root (main.ts): the only place that picks implementations
const checkout = new CheckoutService(new CardProviderGateway(apiKey), new SqlOrderRepository(pool));

// In a test: a fake, no network
const fakePayments: PaymentGateway = { charge: async () => ({ ok: false }) };
const service = new CheckoutService(fakePayments, new InMemoryOrderRepository());
await expect(service.checkout(cart)).rejects.toThrow('Payment declined');
```

## A chef and a supplier

A chef who grows every ingredient personally cannot change suppliers. A chef who has ingredients delivered can switch from one farm to another, or practise with plastic vegetables, without changing how they cook.

**Quiz:** What is the "composition root" in dependency injection?

- [ ] A global variable holding every object
- [ ] The base class of all services
- [x] The single place, usually at startup, where concrete implementations are created and wired together
- [ ] The first database table created

*Answer:* The single place, usually at startup, where concrete implementations are created and wired together. Wiring happens once, at the edge of the application.
