Інтерфейс Сегрегація Принцип говорить:
Жоден клієнт не повинен бути змушений залежати від методів, які він не використовує. ISP розбиває дуже великі інтерфейси на більш дрібні та конкретні, тому клієнтам потрібно буде знати лише про цікаві для них методи.
Тут є кілька питань без відповіді. Одне:
Як маленький?
Ти кажеш:
В даний час я займаюся цим, розділяючи простір імен модуля залежно від потреб його клієнтів.
Я називаю це ручне введення качки . Ви будуєте інтерфейси, які розкривають лише те, що потрібно клієнту. Принцип поділу інтерфейсу - це не просто ручне введення качок.
Але ISP - це не просто заклик до "узгоджених" рольових інтерфейсів, які можна використовувати повторно. Жоден "узгоджений" дизайн рольового інтерфейсу не може ідеально захистити від додавання нового клієнта з власними рольовими потребами.
ISP - це спосіб ізолювати клієнтів від впливу змін у сервісі. Потрібно було зробити збірку швидшою, коли ви вносите зміни. Звичайно, це має інші переваги, як, наприклад, не ламати клієнтів, але це було головним моментом. Якщо я змінюю count()
підпис функції сервісу, це добре, якщо клієнтам, які не користуються count()
, не потрібно редагувати та перекомпілювати.
Це ЧОМУ я дбаю про принцип сегрегації інтерфейсів. Я не вважаю, що віра є важливою. Це вирішує справжню проблему.
Тож спосіб його застосування повинен вирішити проблему для вас. Не існує жодного способу відмовитись від мозку, щоб застосувати провайдер, який не можна перемогти лише правильним прикладом необхідних змін. Ви повинні подивитися на те, як система змінюється, і зробити вибір, який дозволить спокійно впоратись. Давайте вивчимо варіанти.
Спершу запитайте себе: чи важко змінити інтерфейс служби зараз? Якщо ні, виходьте на вулицю і грайте, поки не заспокоїтесь. Це не інтелектуальна вправа. Будь ласка, переконайтеся, що вилікування не гірше захворювання.
Якщо багато клієнтів використовують один і той же підмножина функцій, це аргументується "узгодженими" багаторазовими інтерфейсами. Підмножина, ймовірно, зосереджена на одній ідеї, яку ми можемо розглядати як роль, яку надає послуга клієнту. Приємно, коли це працює. Це не завжди працює.
Якщо багато клієнтів використовують різні підмножини функцій, можливо, клієнт насправді використовує послугу через кілька ролей. Це нормально, але ролі важко помітити. Знайдіть їх і спробуйте розірвати їх на частини. Це може повернути нас у випадку 1. Клієнт просто використовує послугу через більш ніж один інтерфейс. Будь ласка, не починайте кастинг послуги. Якщо що-небудь, це означало б передачу послуги клієнту не раз. Це працює, але це змушує мене сумніватися, чи служба не є великою кулькою грязі, яку потрібно розбити.
Якщо багато клієнтів використовують різні підмножини, але ви не бачите ролей, навіть дозволяючи клієнтам використовувати більше ніж один, тоді вам не краще, ніж набирати качки, щоб створити інтерфейси навколо. Такий спосіб проектування інтерфейсів гарантує, що клієнт не піддається впливу навіть однієї функції, яку він не використовує, але майже гарантує, що додавання нового клієнта завжди передбачає додавання нового інтерфейсу, який, хоча для реалізації служби не потрібно знати про нього буде інтерфейс, який агрегує рольові інтерфейси. Ми просто торгували одним болем за іншим.
Якщо багато клієнтів використовують різні підмножини, перекриваються, очікується додавання нових клієнтів, які потребуватимуть непередбачуваних підмножин, і ви не бажаєте розбивати послугу, тоді розглядайте більш функціональне рішення. Оскільки перші два варіанти не спрацювали, і ви насправді в поганому місці, де нічого не слідує шаблону, і вноситься більше змін, тоді подумайте про надання кожній функції власного інтерфейсу. Покінчити тут не означає, що провайдер провалився. Якщо щось не вдалося, це була об'єктно-орієнтована парадигма. Інтерфейси єдиного методу слідують провайдеру в крайніх випадках. Це досить трохи введення клавіатури, але ви можете виявити, що це раптом робить інтерфейси багаторазовими. Знову ж таки, будьте впевнені, що немає
Тож виявляється, вони дійсно можуть отримати дуже малі.
Я сприйняв це питання як завдання застосувати Інтернет-провайдер в самих крайніх випадках. Але майте на увазі, що крайнощів найкраще уникати. У продуманому дизайні, який застосовує інші принципи SOLID, ці проблеми зазвичай не виникають і не мають значення, майже стільки ж.
Ще одне питання без відповіді:
Кому належать ці інтерфейси?
Попереду я бачу інтерфейси, розроблені з тим, що я називаю "бібліотечним" менталітетом. Всі ми були винні в кодуванні мавпи-бачити-мавпи-робити, де ви просто щось робите, бо саме так ви бачили це. Ми винні в тому ж, що з інтерфейсами.
Коли я дивлюся на інтерфейс, призначений для класу в бібліотеці, я думав: о, ці хлопці - професіонали. Це повинен бути правильним способом зробити інтерфейс. Мені не вдалося зрозуміти, що межа бібліотеки має власні потреби та проблеми. З одного боку, бібліотека зовсім не знає дизайну своїх клієнтів. Не кожна межа однакова. І іноді навіть одна і та ж межа має різні способи її перетину.
Ось два простих способи розглянути дизайн інтерфейсу:
Інтерфейс, що належить сервісу. Деякі люди розробляють кожен інтерфейс, щоб викрити все, що може зробити послуга. Ви навіть можете знайти параметри рефакторингу в IDE, які будуть писати інтерфейс для вас, використовуючи будь-який клас, яким ви його подаєте.
Клієнтський інтерфейс. ISP, здається, стверджує, що це правильно, а служба, що належить, неправильна. Ви повинні мати на увазі кожен інтерфейс із потребами клієнтів. Оскільки клієнт має інтерфейс, він повинен його визначити.
То хто прав?
Розгляньте плагіни:
Кому належать тут інтерфейси? Клієнти? Послуги?
Виходить і те, і інше.
Кольори тут - шари. Червоний шар (праворуч) не повинен нічого знати про зелений шар (зліва). Зелений шар можна змінити або замінити, не торкаючись червоного шару. Таким чином будь-який зелений шар може бути підключений до червоного шару.
Мені подобається знати, що слід знати про те, а що не слід знати. Для мене "що знає про що?" - єдине найважливіше архітектурне питання.
Зробимо зрозумілий лексику:
[Client] --> [Interface] <|-- [Service]
----- Flow ----- of ----- control ---->
Клієнт - це те, що використовує.
Послуга - це те, що використовується.
Interactor
трапляється і те, і інше.
ISP каже, що розбиваються інтерфейси для клієнтів. Добре, давайте застосувати це тут:
Presenter
(послуга) не повинна диктувати Output Port <I>
інтерфейс. Інтерфейс повинен бути звужений до того, що Interactor
(тут виступаючи як клієнт) потрібно. Це означає, що інтерфейс ЗНАЄ про Interactor
та, щоб слідкувати за ISP, повинен змінюватися разом із ним. І це прекрасно.
Interactor
(тут виступає в ролі служби) не повинно диктувати Input Port <I>
інтерфейс. Інтерфейс повинен бути звужений до того, що потрібно Controller
(клієнту). Це означає, що інтерфейс ЗНАЄ про Controller
та, щоб слідкувати за ISP, повинен змінюватися разом із ним. І це не добре.
Другий - не добре, оскільки червоний шар не повинен знати про зелений шар. Так помиляється ISP? Добре начебто. Жоден принцип не є абсолютним. Це випадок, коли кози, яким подобається інтерфейс, щоб показати все, що може зробити служба, виявляються правильними.
Принаймні, вони мають рацію, якщо Interactor
не роблять нічого іншого, ніж це потребує випадку використання. Якщо це Interactor
робиться для інших випадків використання, немає ніяких причин, це Input Port <I>
повинно знати про них. Не впевнений, чому Interactor
не можна просто зосередитись на одному випадку використання, тому це не проблема, але все відбувається.
Але input port <I>
інтерфейс просто не може вести себе Controller
клієнту, і це може бути справжнім плагіном. Це межа "бібліотеки". Зовсім інший магазин програмування може писати зелений шар через роки після публікації червоного шару.
Якщо ви перетинаєте межу "бібліотеки" і відчуваєте необхідність застосовувати провайдер, хоча ви не володієте інтерфейсом з іншого боку, вам доведеться знайти спосіб звузити інтерфейс, не змінюючи його.
Один із способів зняти це - адаптер. Розмістіть його між клієнтами типу Controler
та Input Port <I>
інтерфейсом. Адаптер приймає Interactor
як Input Port <I>
і передає свою роботу йому. Однак він відкриває лише те, що Controller
потрібно клієнтам через рольовий інтерфейс або інтерфейси, що належать зеленому шару. Адаптер не відповідає ISP, але дозволяє більш складним класам, як Controller
насолоджуватися ISP. Це корисно, якщо є менше адаптерів, ніж такі Controller
, як користуються клієнти , і коли ви перебуваєте в незвичній ситуації, коли ви перетинаєте межу бібліотеки, і, незважаючи на публікацію, бібліотека не перестане змінюватися. Дивлячись на тебе Firefox. Тепер ці зміни розбивають лише ваші адаптери.
То що це означає? Це означає, чесно, ви не надали мені достатньо інформації, щоб сказати, що вам робити. Я не знаю, якщо недотримання ISP викликає у вас проблему. Я не знаю, якщо дотримання цього не призведе до більшої кількості проблем.
Я знаю, ви шукаєте простий керівний принцип. ISP намагається бути таким. Але це залишає багато не сказаного. Я вірю в це. Так, будь ласка, не змушуйте клієнтів залежати від методів, якими вони не користуються, без поважних причин!
Якщо у вас є вагомі причини, як-от розробка дизайну для прийняття плагінів, знайте про проблеми, які не слідкують за причинами провайдера (важко змінити, не порушуючи клієнтів), і способи їх пом'якшення (зберегти Interactor
або принаймні Input Port <I>
зосередитись на одному стабільному випадок використання).