# Dependency Inversion Principle (DIP)

> Depend on abstractions, not concrete implementations — both sides of a boundary point at an interface, not at each other.

- **Category**: Solid
- **Subcategory**: principles
- **Canonical URL**: https://designpattern.fyi/solid/dependency-inversion-principle-dip/

---

## Description
**Intent**: High-level business logic directly coupled to a specific database, API, or service can't be tested, swapped, or evolved without changing the business code itself.

**Context**: OrderProcessor instantiates MySQLDatabase directly. You can't test OrderProcessor without a real database. Switching to MongoDB means editing the business logic class. The high-level policy is at the mercy of a low-level implementation detail.

**Solution**: Define an interface (Database). OrderProcessor depends on the interface. MySQLDatabase and MongoDBDatabase both implement it. The concrete implementation is injected at runtime. Now both layers point at the abstraction — neither layer knows the other exists.



## Use Cases
Decoupling system layers so they can vary independently. Making code testable with mock implementations. Supporting multiple concrete implementations of the same dependency (databases, payment gateways, notification services, file storage).



## Implementation Example

```javascript
// Before: Direct dependency on concretion
class OrderProcessor {
  constructor() {
    this.database = new MySQLDatabase(); // Direct dependency
  }

  processOrder(order) {
    this.database.save(order);
  }
}

// After: DIP applied
class Database {
  save(data) {
    throw new Error('Must implement save');
  }
}

class MySQLDatabase extends Database {
  save(data) {
    console.log(`Saving to MySQL: ${data}`);
  }
}

class MongoDBDatabase extends Database {
  save(data) {
    console.log(`Saving to MongoDB: ${data}`);
  }
}

class OrderProcessor {
  constructor(database) {
    this.database = database; // Depends on abstraction
  }

  processOrder(order) {
    this.database.save(order);
  }
}

// Can easily swap implementations
const processor1 = new OrderProcessor(new MySQLDatabase());
const processor2 = new OrderProcessor(new MongoDBDatabase());
```



## Trade-offs


### Advantages

- Loose coupling — swap any implementation without touching the caller

- Easy to test with mocks or stubs injected at any boundary

- High-level business logic is insulated from low-level churn




### Considerations & Drawbacks

- More indirection — every dependency adds an interface and an injection point

- Requires upfront abstraction design — wrong abstractions are expensive to reverse

- Overkill for simple scripts or throwaway code with no testing requirement







