2 Dependency Injection
Dependency Injection (DI) is a design pattern in software engineering that deals with how objects acquire their dependencies (i.e., other objects or resources they need to function).
2.0.1 🧠 Concept Overview
- “Dependency”: An object or service that another object depends on.
- “Injection”: Providing that dependency from outside rather than letting the object create it by itself.
Instead of a class instantiating its dependencies (tight coupling), they are passed in (injected) from the outside (loose coupling).
This helps improve:
- Modularity
- Testability
- Flexibility
2.0.2 🔧 Types of Dependency Injection
| Type | How it’s Injected |
|---|---|
| Constructor Injection | Via constructor parameters |
| Setter Injection | Via setter methods or public properties |
| Interface Injection | The dependency provides an injector interface |
2.0.3 🧪 Example in Python (Constructor Injection)
Let’s say we have a DatabaseService that’s used in a UserRepository:
2.0.3.1 🔴 Without Dependency Injection (Tightly Coupled)
class UserRepository:
def __init__(self):
self.db = DatabaseService() # hard-coded dependency
def get_user(self, user_id):
return self.db.query(f"SELECT * FROM users WHERE id = {user_id}")UserRepositorycreates theDatabaseService→ hard to test or reuse with another DB.
2.0.3.2 🟢 With Dependency Injection (Loosely Coupled)
class UserRepository:
def __init__(self, db_service):
self.db = db_service # dependency injected from outside
def get_user(self, user_id):
return self.db.query(f"SELECT * FROM users WHERE id = {user_id}")Now you can pass in any db_service:
# Example concrete dependency
class DatabaseService:
def query(self, sql):
print(f"Executing SQL: {sql}")
# Use dependency injection
db = DatabaseService()
repo = UserRepository(db)
repo.get_user(123)You can easily mock or replace the DatabaseService in testing:
# A mock dependency
class MockDatabaseService:
def query(self, sql):
return {"id": 123, "name": "Test User"}
mock_repo = UserRepository(MockDatabaseService())
print(mock_repo.get_user(123)) # → {'id': 123, 'name': 'Test User'}2.0.4 🧩 Summary Table
| Feature | Without DI | With DI |
|---|---|---|
| Dependency creation | Inside the class | Outside the class |
| Coupling | Tight | Loose |
| Testability | Hard (need real objects) | Easy (mock dependencies) |
| Flexibility | Low | High |