OOP Course
Сьогодні

Підрозділ 20.6

DIP — Принцип інверсії залежностей

20.6. DIP — Принцип інверсії залежностей Dependency Inversion Principle DIP — п'ятий і в певному сенсі найвагоміший принцип SOLID, бо він підсумовує і об'єднує всі попередні. Сформулював його Роберт Мартін у 19

20.6. DIP — Принцип інверсії залежностей

Dependency Inversion Principle (DIP) — п'ятий і в певному сенсі найвагоміший принцип SOLID, бо він підсумовує і об'єднує всі попередні. Сформулював його Роберт Мартін у 1994–1996 роках. Принцип складається з двох частин:

  1. Модулі верхнього рівня не повинні залежати від модулів нижнього рівня. Обидва мають залежати від абстракцій.
  2. Абстракції не повинні залежати від деталей. Деталі мають залежати від абстракцій.

Щоб зрозуміти ці слова конкретно: «модуль верхнього рівня» — це бізнес-логіка (AppointmentService, PatientService), а «модуль нижнього рівня» — це інфраструктура (SqlRepository, SmtpNotifier, FileLogger). «Деталь» — це конкретна реалізація (SQL, SMTP, CSV). «Абстракція» — це інтерфейс або абстрактний клас, що описує лише що треба зробити, але не як.

Без DIP бізнес-логіка знає про конкретну базу даних, конкретний поштовий шлюз, конкретний файловий формат. Зміна будь-якого з них вимагає змін у бізнес-логіці. Тест бізнес-логіки потребує реального SQL-сервера. Це й є «неправильний напрямок залежностей» — бізнес залежить від деталей.

Інверсія — не означає «перевернути все з ніг на голову». Вона означає: хто диктує умови? Без DIP — деталь (SQL) диктує умови бізнес-логіці. З DIP — бізнес-логіка диктує умови (через інтерфейс), а деталь їх виконує.

Пряма залежність: проблема

DIP — інверсія напряму залежностей через абстракцію

Рефакторинг: вводимо абстракцію

Рішення — виразити потреби бізнес-логіки через інтерфейс. Бізнес-логіка тепер залежить від абстракції IAppointmentRepository, а не від конкретного SqlAppointmentRepository. Конкретна реалізація «вводиться» ззовні — через конструктор (Dependency Injection).

Dependency Injection: три способи введення залежностей

DIP визначає принцип («залежте від абстракцій»), а Dependency Injection (DI) — механізм його реалізації. DI — це патерн, що описує, як саме залежність «вводиться» (inject) у клас ззовні. Є три основних способи:

Constructor Injection є загальновизнаним стандартом для обов'язкових залежностей: клас не може існувати без своїх залежностей, тому вони передаються в конструкторі. Property Injection і Method Injection вживаються значно рідше — лише тоді, коли залежність справді необов'язкова або специфічна для одного виклику.

DI-контейнер: автоматичне керування залежностями

У великих системах ланцюжки залежностей стають довгими: AppointmentServiceIAppointmentRepositoryIDbConnection → ... Вручну конструювати всю ієрархію об'єктів у Program.cs нереально. Для цього існують DI-контейнери — бібліотеки, що автоматично вирішують, яку реалізацію підставити для кожного інтерфейсу.

У .NET стандартний DI-контейнер — Microsoft.Extensions.DependencyInjection. Він реєструє «прив'язки» (interface → implementation) і сам конструює об'єкти з потрібними залежностями:

DIP і тестованість: підроблені залежності

Найпрактичніша перевага DIP — можливість підміняти залежності у тестах. Якщо клас залежить від IAppointmentRepository, а не від SqlAppointmentRepository, тест може передати «підроблений» репозиторій, що повертає заздалегідь задані дані:

Три тести — жодного SQL, жодного файлу, жодної мережі. Кожен тест налаштовує FakeAppointmentStore у потрібний стан і перевіряє лише бізнес-логіку SchedulingService. Це і є головна практична цінність DIP.

Підсумок розділу 20: SOLID як єдина система

Хоча кожен принцип можна вивчати окремо, вони утворюють єдину архітектурну систему:

Розроблено Tomka Yurii · © 2026 ·