# Dependency Injection (DI)

Dependency Injection is a design pattern in which an object receives other objects that it depends on. These other objects are called **dependencies**.

## 1. The Core Concept

In traditional programming, if Class A needs Class B, Class A creates an instance of Class B.
*   **Tight Coupling:** Class A is hard-coded to use Class B. You can't easily swap Class B for Class C or a Mock version for testing.

With Dependency Injection, Class A **asks** for Class B (usually in its constructor), and something else (the "Injector" or "Container") provides it.

## 2. The Problem: Tight Coupling

```typescript
class Engine {
    start() { console.log("Vroom"); }
}

class Car {
    private engine: Engine;

    constructor() {
        // The Car is responsible for creating its own Engine.
        // Hard to test: We can't swap this for a MockEngine.
        this.engine = new Engine(); 
    }
}
```

## 3. The Solution: Injection

We move the creation of the dependency *outside* the class.

```typescript
class Car {
    private engine: Engine;

    // The dependency is "injected" via the constructor.
    constructor(engine: Engine) {
        this.engine = engine;
    }
}

// Usage
const myEngine = new Engine();
const myCar = new Car(myEngine);
```

## 4. Types of Injection

### Constructor Injection
Dependencies are provided through the class constructor. This is the most common and recommended method because it ensures the object is always in a valid state (all dependencies are present upon creation).

### Setter Injection
Dependencies are provided through public properties or setter methods.
*   **Pros:** Flexible (can change dependencies later).
*   **Cons:** The object might be in an invalid state between creation and injection.

## 5. Benefits

1.  **Decoupling:** Classes don't need to know how to create their dependencies.
2.  **Testability:** You can easily inject **Mock Objects** during unit tests.
    *   *Real World:* Inject `DatabaseService`.
    *   *Test World:* Inject `MockDatabaseService` (in-memory).
3.  **Maintainability:** Code is easier to read and modify.

## 6. DI Containers

In large applications, manually creating and passing dependencies (`new A(new B(new C()))`) becomes tedious. **DI Containers** (or IoC Containers) automate this.

*   **Examples:** Spring (Java), Angular (TS), NestJS (TS), Dagger (Android).
*   The container manages the lifecycle of objects and automatically injects dependencies when needed.

## 7. Inversion of Control (IoC)

Inversion of Control is a broader design principle where the control flow of a program is inverted: instead of the programmer controlling the flow of the application, the framework or container controls it.

*   **Traditional Control:** Your custom code calls the library/framework code.
*   **Inversion of Control:** The framework calls your custom code.

### The Hollywood Principle
IoC is often summarized as: **"Don't call us, we'll call you."**

### Relationship to Dependency Injection
Dependency Injection is a specific form of IoC.
*   **IoC:** The general concept of inverting control.
*   **DI:** Specifically inverting the control of *creating dependencies*. Instead of the class creating its dependencies, something else (the IoC Container) creates them and injects them.

## 8. Circular Dependencies

A circular dependency occurs when two or more classes depend on each other. For example, Class A depends on Class B, and Class B depends on Class A.

### The Problem
If you use Constructor Injection, the DI container (or your manual code) gets stuck in an infinite loop trying to instantiate them:
1.  To create A, I need B.
2.  To create B, I need A.
3.  To create A, I need B...
*   **Result:** Stack Overflow or Runtime Error.

### Solutions
1.  **Redesign (Best):** Often, a circular dependency implies a design flaw. Extract the shared logic into a third service (Class C) that both A and B depend on.
2.  **Setter Injection:** Use constructor injection for one, and setter injection for the other. This allows both objects to be created before they are linked.
3.  **Forward Reference / Lazy:** Many DI frameworks (like NestJS or Angular) provide a `forwardRef()` function to delay the resolution of the dependency until it is needed.

[[programming/solid-principles]]
[[programming/design-patterns]]
[[programming/software-testing-basics]]
[[programming/object-oriented-programming]]