Підрозділ 20.5
ISP — Принцип розподілу інтерфейсів
20.5. ISP — Принцип розподілу інтерфейсів Interface Segregation Principle ISP сформулював Роберт Мартін у 1996 році у статті для журналу C++ Report. Принцип звучить так: «Клієнти не повинні залежати від методів
20.5. ISP — Принцип розподілу інтерфейсів
Interface Segregation Principle (ISP) сформулював Роберт Мартін у 1996 році у статті для журналу C++ Report. Принцип звучить так: «Клієнти не повинні залежати від методів, яких вони не використовують». Або у іншому формулюванні: «Краще багато вузькоспеціалізованих інтерфейсів, ніж один великий».
ISP — це принцип про проектування інтерфейсів з точки зору клієнта. Інтерфейс «поганий» не тому, що він великий сам по собі, а тому, що він змушує реалізатора брати на себе зобов'язання, які йому не потрібні. Якщо клас ReceptionDesk реалізує IClinicService і мусить написати GeneratePdfReport() та ExportToCsv() — хоча йому вони ніколи не знадобляться — це і є порушення ISP.
Наслідки такого «жирного» інтерфейсу (fat interface):
- Реалізатор пише «заглушки» — методи, що кидають
NotImplementedExceptionабо просто нічого не роблять - Зміна в інтерфейсі (навіть у методах, що клас не використовує) вимагає перекомпіляції і перевірки всіх реалізаторів
- Тест на
ReceptionDeskраптом залежить від PDF-бібліотеки, хочаReceptionDeskз PDF нічого спільного не має
«Жирний» інтерфейс: класична помилка
Коли систему проектують поспіхом або «зверху вниз» без аналізу клієнтів, природно з'являється один великий інтерфейс, що об'єднує всі можливості системи:

Рефакторинг: розбиття на вузькі інтерфейси
Відповідно до ISP, кожна «група» методів, що обслуговує окремого клієнта, стає окремим інтерфейсом. Клас реалізує стільки інтерфейсів, скільки «ролей» він виконує:

ISP і принцип найменшого знання
ISP тісно пов'язаний із «принципом найменшого знання» (Principle of Least Knowledge або Law of Demeter): компонент повинен знати якомога менше про решту системи. Якщо ReceptionDesk реалізує IReportService, він «знає» про PDF і Email — навіть якщо сам їх не використовує. Вузькі інтерфейси природно мінімізують це «зайве знання».
ISP у реальному коді: інтерфейси як «ролі»
Хороший спосіб думати про ISP: кожен інтерфейс — це роль, яку клас може виконувати. Один клас може грати кілька ролей. Роль описана мінімально: лише те, що потрібно клієнту цієї ролі.
Коли ISP не потрібен
Варто розуміти: ISP — не заклик дробити кожен інтерфейс до одного методу. Інтерфейс IComparable<T> з одним методом CompareTo — правильний приклад вузького інтерфейсу. Але IEnumerable<T> з одним GetEnumerator — теж правильний. Розмір інтерфейсу не є самоціллю.
Інтерфейс потрібно розбивати тоді, коли різні клієнти використовують різні підмножини методів. Якщо всі клієнти використовують всі методи — об'єднаний інтерфейс абсолютно правильний. Критерій: «Чи є хоч один клієнт, що змушений залежати від методу, який йому не потрібен?» — якщо так, ISP застосовується.
Клас PatientDashboard залежить від трьох методів ILabResultProvider, а не від усього великого API лабораторної системи. Якщо лабораторна система повністю замінюється — пишеться новий адаптер, PatientDashboard не змінюється.