Inversion of Control (IoC) Trong Python: Hướng Dẫn Chi Tiết

Đăng ngày: 20/06/2026 • Tác giả: Quản trị viên
Inversion of Control (IoC) Trong Python: Hướng Dẫn Chi Tiết

Inversion of Control (IoC) Trong Python: Hướng Dẫn Chi Tiết

📌 Nội dung chính:

1️⃣ Inversion of Control (IoC) là gì?
2️⃣ Sự khác biệt giữa IoC và Dependency Injection (DI)
3️⃣ Các cách triển khai IoC trong Python
4️⃣ Sử dụng IoC Container trong Python
5️⃣ IoC trong thực tế với Flask


1. Inversion of Control (IoC) là gì?

💡 Inversion of Control (IoC) là một nguyên tắc trong lập trình giúp tách biệt việc quản lý và tạo dependency ra khỏi class, từ đó giúp code linh hoạt và dễ mở rộng hơn.

🚀 Thay vì để class tự tạo hoặc quản lý dependency của nó, một thành phần khác sẽ chịu trách nhiệm làm điều đó.

🔍 Ví dụ: Không có IoC

class Database:
    def connect(self):
        return "Kết nối MySQL"

class UserService:
    def __init__(self):
        self.db = Database()  # Tạo trực tiếp dependency

    def get_user(self):
        return f"User từ {self.db.connect()}"

🚨 Vấn đề:

  • UserService tự tạo Database, khiến nó bị phụ thuộc cứng vào Database.
  • Nếu muốn đổi sang MongoDB, ta phải sửa lại UserService.

🔍 Ví dụ: Có IoC (với DI)

class Database:
    def connect(self):
        return "Kết nối MySQL"

class UserService:
    def __init__(self, database):  # Dependency Injection
        self.db = database

    def get_user(self):
        return f"User từ {self.db.connect()}"

db = Database()
user_service = UserService(db)  # IoC: Dependency được truyền từ bên ngoài
print(user_service.get_user())

📌 Lợi ích:
✔ UserService không bị khóa vào Database nữa.
✔ Có thể thay đổi Database mà không cần sửa UserService.

2. Sự khác biệt giữa IoC và Dependency Injection (DI)

🔎 IoC là nguyên tắc giúp tách biệt việc quản lý dependency.
🔎 Dependency Injection (DI) là một kỹ thuật triển khai IoC bằng cách truyền dependency từ bên ngoài vào.

💡 DI là một cách thực hiện IoC, nhưng IoC không chỉ giới hạn ở DI.

3. Các Cách Triển Khai IoC Trong Python

1. Factory Pattern (Tạo Dependency Thông Qua Factory)

Thay vì khởi tạo trực tiếp dependency, ta dùng một Factory để tạo chúng.

class Database:
    def connect(self):
        return "Kết nối MySQL"

class DatabaseFactory:
    @staticmethod
    def create():
        return Database()  # Trả về instance của Database

class UserService:
    def __init__(self, database):
        self.db = database

    def get_user(self):
        return f"User từ {self.db.connect()}"

db = DatabaseFactory.create()  # IoC: Factory quản lý việc tạo instance
user_service = UserService(db)
print(user_service.get_user())

📌 Lợi ích:
✔ UserService không biết Database được tạo như thế nào.
✔ Dễ dàng thay đổi loại Database.

2. Service Locator Pattern

Dùng một lớp trung gian để lưu trữ và cung cấp dependency khi cần.

class ServiceLocator:
    _services = {}

    @staticmethod
    def register(name, service):
        ServiceLocator._services[name] = service

    @staticmethod
    def get(name):
        return ServiceLocator._services.get(name)

class Database:
    def connect(self):
        return "Kết nối MySQL"

class UserService:
    def __init__(self):
        self.db = ServiceLocator.get("database")

    def get_user(self):
        return f"User từ {self.db.connect()}"

# Đăng ký service trước khi sử dụng
ServiceLocator.register("database", Database())

user_service = UserService()
print(user_service.get_user())

📌 Lợi ích:
✔ UserService không cần biết Database được tạo như thế nào.
✔ Có thể thay đổi Database ở một nơi duy nhất.

3. IoC Container

IoC Container giúp quản lý dependency tự động.

📌 Dùng thư viện dependency_injector để triển khai IoC Container.

Cài đặt thư viện:

pip install dependency-injector

👉 Cách triển khai IoC Container trong Python

from dependency_injector import containers, providers

class Database:
    def connect(self):
        return "Kết nối MySQL"

class UserService:
    def __init__(self, database):
        self.db = database

    def get_user(self):
        return f"User từ {self.db.connect()}"

# Định nghĩa IoC Container
class Container(containers.DeclarativeContainer):
    database = providers.Singleton(Database)
    user_service = providers.Factory(UserService, database=database)

# Lấy instance từ container
container = Container()
user_service = container.user_service()
print(user_service.get_user())

📌 Lợi ích:
✔ UserService không cần biết Database được tạo thế nào.
✔ IoC Container tự động quản lý dependency.

4. IoC Trong Thực Tế Với Flask

Khi dùng Flask, ta có thể sử dụng IoC để quản lý dependency giữa các service.

from flask import Flask
from dependency_injector import containers, providers

app = Flask(__name__)

class Database:
    def connect(self):
        return "Kết nối MySQL"

class UserService:
    def __init__(self, database):
        self.db = database

    def get_user(self):
        return {"name": "Thảo", "data": self.db.connect()}

# IoC Container
class Container(containers.DeclarativeContainer):
    database = providers.Singleton(Database)
    user_service = providers.Factory(UserService, database=database)

container = Container()

@app.route("/user")
def get_user():
    user_service = container.user_service()
    return user_service.get_user()

if __name__ == "__main__":
    app.run(debug=True)

📌 Lợi ích:
✔ Tách biệt logic, giúp code dễ bảo trì.
✔ Có thể thay thế Database dễ dàng mà không sửa UserService.

5. Khi Nào Nên Sử Dụng IoC?

✅ Khi làm việc với hệ thống lớn có nhiều dependency.
✅ Khi muốn tách biệt các thành phần để dễ bảo trì.
✅ Khi muốn kiểm thử dễ dàng hơn.
✅ Khi sử dụng Flask, FastAPI hoặc các framework lớn.

🚨 Không nên dùng IoC nếu:

  • Ứng dụng quá nhỏ, không có nhiều dependency.

6. Tổng Kết

✔ IoC giúp tách biệt việc quản lý dependency, làm cho code linh hoạt hơn.
✔ Có nhiều cách triển khai IoC trong Python: Factory, Service Locator, IoC Container.
✔ Flask có thể kết hợp IoC để quản lý service hiệu quả hơn.

💡 Bạn có câu hỏi gì về IoC? Hãy để lại bình luận bên dưới!

Bài viết liên quan