Skip to main content

Як впровадити DI у багатошаровій архітектурі?

DI (Dependency Injection) - це спосіб впровадження залежностей між шарами так, щоб кожен шар не створював об'єкти сам, а отримував їх «ззовні»: через конструктор, параметри або контейнер залежностей.

У багатошаровій архітектурі DI потрібен, щоб послабити зв'язки між шарами і зробити систему гнучкою, тестованою та керованою.


1. Проблема без DI

Без впровадження залежностей код виглядає так:

python
class UserService: def __init__(self): self.repository = UserRepository() # залежність створюється всередині

Тепер UserService жорстко прив'язаний до конкретної реалізації UserRepository. Якщо ти захочеш замінити базу або протестувати сервіс - доведеться переписувати код.


2. Принцип DI у багатошаровій архітектурі

Ідея в тому, щоб кожен шар не створював залежність, а отримував її «готовою» від верхнього рівня або контейнера:

python
class UserService: def __init__(self, repository): self.repository = repository

Тепер можна передати будь-яку реалізацію:

python
repo = PostgresUserRepository() service = UserService(repo)

UserService більше не залежить від того, яка база використовується. → Тести можуть підставити FakeRepository.


3. Де впроваджувати залежності по шарах

ШарЩо впроваджуєтьсяКуди
Презентаційний шарСервіси бізнес-логікиУ контролери / view
Бізнес-логічний шарРепозиторії, провайдериУ сервіси / менеджери
Шар данихПідключення, драйвериУ репозиторії
Інфраструктурний шарКеш, логери, API-клієнтиУ сервіси або обробники подій

4. Як це виглядає в реальності

Приклад на Python (без фреймворків):

python
class UserRepository: def get_user(self, id): ... class UserService: def __init__(self, repository): self.repository = repository def get_user_info(self, id): user = self.repository.get_user(id) return {"name": user.name, "email": user.email} class UserController: def __init__(self, service): self.service = service def handle_request(self, id): return self.service.get_user_info(id) # Впровадження залежностей на верхньому рівні: repository = UserRepository() service = UserService(repository) controller = UserController(service)

5. DI-контейнери (автоматизація)

У великих проєктах використовують DI-контейнер - компонент, який сам створює і передає залежності в потрібні місця:

  • Python: dependency-injector, injector
  • Java: Spring Framework (@Autowired)
  • C#: .NET Core Dependency Injection
  • JavaScript/TS: NestJS, InversifyJS

Контейнер керує всім деревом залежностей:

python
container = Container() container.wire(modules=[controllers, services, repositories])

6. Головне правило

Залежності завжди спрямовані вниз - верхній шар знає про нижній, але не навпаки.

DI дозволяє змінити реалізацію нижнього шару, не чіпаючи верхній.


Підсумок: DI у багатошаровій архітектурі - це механізм, який впроваджує зв'язки між шарами через інтерфейси, а не через жорстке створення об'єктів. Він робить код гнучким, тестованим і готовим до масштабування без «ефекту доміно».

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.