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}")
UserRepository
creates 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
= DatabaseService()
db = UserRepository(db)
repo 123) repo.get_user(
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"}
= UserRepository(MockDatabaseService())
mock_repo 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 |