Розділити великі інтерфейси


9

Я використовую великий інтерфейс з приблизно 50 методами для доступу до бази даних. Інтерфейс написав мій колега. Ми обговорювали це:

Я: 50 методів - це занадто багато. Це кодовий запах.
Колега: Що з цим робити? Ви хочете отримати доступ до БД - у вас є.
Я: Так, але це незрозуміло і важко піддаватися подальшому.
Колега: Гаразд, ви праві, це не приємно. Як повинен виглядати інтерфейс тоді?
Я: Як щодо 5 методів, які повертають об'єкти, які мають, наприклад, 10 методів кожен?

Ммм, але хіба це не було б саме? Чи справді це призводить до більшої ясності? Чи варто докладати зусиль?

Раз у раз я знаходжусь у ситуації, коли мені хочеться інтерфейс, і перше, що спадає на думку, - це один великий інтерфейс. Чи існує загальна модель дизайну для цього?


Оновлення (відповідаючи на коментар SJuan):

"Вид методів": це інтерфейс для отримання даних із бази даних. Усі методи мають вигляд (псевдокод)

List<Typename> createTablenameList()

Методи та таблиці знаходяться не у співвідношенні 1-1, акцент робиться більше на тому, що ви завжди отримуєте якийсь список, який походить із бази даних.


12
Відсутня відповідна інформація (які методи ви маєте). У будь-якому разі, я здогадуюсь: якщо ти ділиш лише число, то колега має рацію, ти нічого не вдосконалюєш. Один з можливих критеріїв поділу повернувся б "суттю" (майже еквівалент таблиці) (таким чином, a UserDaoі a CustomerDaoі a ProductDao)
SJuan76

Дійсно, деякі таблиці семантично близькі до інших таблиць, що утворюють "кліки". Так і роблять методи.
TobiMcNamobi

Чи можливо побачити код? Я знаю, що йому 4 роки, і ви, мабуть, це вже вирішили: D Але я б хотів подумати над цією проблемою. Я вирішив щось подібне раніше.
clankill3r

@ clankill3r Дійсно, у мене вже немає доступу до певного інтерфейсу, який змусив мене опублікувати вищезазначене питання. Однак проблема є більш загальною. Уявіть БД з приблизно 50 таблицями і для кожної таблиці такий спосіб, якList<WeatherDataRecord> createWeatherDataTable() {db.open(); return db.select("*", "tbl_weatherData");}
TobiMcNamobi

Відповіді:


16

Так, 50 методів - це кодовий запах, але кодовий запах означає ще раз поглянути на це, не те, що це автоматично неправильно. Якщо кожному клієнту, що використовує цей клас, потенційно потрібні всі 50 методів, можливо, це не може бути розбитим. Однак це малоймовірно. Моя думка, розбиття інтерфейсу довільно може бути гіршим, ніж взагалі його розділення.

Не існує єдиної схеми, яка б її виправити, але принцип, який описує бажаний стан, - це принцип інтерфейсу інтерфейсу ("Я" в SOLID), який зазначає, що жоден клієнт не повинен бути змушений залежати від методів, які він не використовує .

Опис провайдера дає вам підказку, як це виправити: подивіться на клієнта . Часто, лише дивлячись на клас, здається, що все належить разом, але чіткі поділи виникають, коли ви дивитесь на клієнтів, які використовують цей клас. Завжди спочатку враховуйте клієнтів, коли розробляєте інтерфейс.

Інший спосіб визначити, чи слід розділяти інтерфейс, це зробити другу реалізацію. Що часто трапляється в тому, що друга ваша реалізація не потребує багато методів, тому їх чітко слід розділити на власний інтерфейс.


Ця відповідь і утнапістім справді чудова.
TobiMcNamobi

13

Колега: Гаразд, ви праві, це не приємно. Як повинен виглядати інтерфейс тоді?

Я: Як щодо 5 методів, які повертають об'єкти, які мають, наприклад, 10 методів кожен?

Це не гарні критерії (насправді в цьому твердженні взагалі немає критеріїв). Ви можете згрупувати їх, якщо у моїх прикладах заявка є додатком для фінансових операцій:

  • функціональність (вставки, оновлення, вибір, транзакції, метадані, схема тощо)
  • сутність (користувач DAO , депозит DAO тощо)
  • область застосування (фінансові операції, управління користувачами, суми тощо)
  • рівень абстракції (весь код доступу до таблиці - це окремий модуль; всі вибрані API є у власній ієрархії, підтримка транзакцій є окремою, весь код перетворення в модулі, весь код перевірки в модулі тощо)

Ммм, але хіба це не було б саме? Чи справді це призводить до більшої ясності? Чи варто докладати зусиль?

Якщо ви обираєте правильні критерії, безумовно. Якщо ви цього не зробите, точно не :).

Кілька прикладів:

  • подивіться на об’єкти ADODB для спрощеного прикладу примітивів OO (ваш API DB, ймовірно, вже пропонує це)

  • подивіться на модель даних Django ( https://docs.djangoproject.com/en/dev/topics/db/models/ ) для ідеї моделі даних з високим рівнем абстракції (у С ++ вам, мабуть, знадобиться трохи більше котла код, але це приємна ідея). Ця реалізація розроблена з урахуванням ролі "моделі" в рамках дизайну MVC.

  • подивіться на API sqlite для ідеї плоскої API ( http://www.sqlite.org/c3ref/funclist.html ), що складається з просто функціональних примітивів (API API).


3

Раз у раз я переживаю ситуацію, коли мені хочеться інтерфейс, і перше, що спадає на думку, - це великий інтерфейс. Чи існує загальна модель дизайну для цього?

Це дизайнерський антидіапазон, який називають монолітним класом . Наявність 50 методів у класі чи інтерфейсі є ймовірним порушенням SRP . Монолітний клас виникає тому, що він намагається бути усім усім.

DCI адреси методу роздуття. По суті, багато обов'язків класу можна було б розподілити за ролями (перевантаженими на інші класи), які мають значення лише в певних контекстах. Застосування ролей може бути досягнуто різними способами, включаючи міксин та декоратори . Такий підхід тримає заняття зосередженими та худорлявими.

Як щодо 5 методів, які повертають об'єкти, у яких, наприклад, 10 методів?

Це говорить про інстанціювання всіх ролей, коли сам об'єкт інстанціюється. Але чому примірникові ролі, можливо, вам не знадобляться? Натомість придумайте роль у тому контексті, в якому вона вам справді потрібна.

Якщо ви виявите, що рефакторинг на DCI не очевидний, ви можете піти з більш простою схемою відвідувачів . Це забезпечує аналогічну перевагу, не підкреслюючи створення контекстів використання.

EDIT: Моє роздуми щодо цього дещо змінило. Я дав альтернативну відповідь.


1

Мені здається, у будь-якій іншій відповіді немає сенсу. Справа в тому, що інтерфейс в ідеалі повинен визначати атомний фрагмент поведінки. Це я в твердому.

Клас повинен нести одну відповідальність, але це все ще може включати в себе багато поведінки. Щоб дотримуватися типового об’єкта клієнтської бази даних, це може запропонувати повну функціональність CRUD. Це було б чотири поведінки: створювати, читати, оновлювати та видаляти. У чистому світі SOLID клієнт бази даних реалізує не IDatabaseClient, а нестійкий ICreator, IReader, IUpdater та IDeleter.

Це матиме ряд переваг. По-перше, лише прочитавши декларацію класу, миттєво дізнаєтесь багато про клас, інтерфейси, які він реалізує, розповідають всю історію. По-друге, якби об’єкт клієнта мав бути переданий як аргумент, тепер у нього є різні корисні варіанти. Це може бути передано як IReader, і можна бути впевненим, що виклик зможе читати тільки. Різні форми поведінки можна перевірити окремо.

Щодо тестування, однак, звичайна практика полягає в тому, щоб просто ляпнути інтерфейс на класі, який є реплікою від 1 до 1 інтерфейсу повного класу. Якщо тестування все, що вам цікаво, це може бути правильним підходом. Це дозволяє робити муляжі досить швидко. Але навряд чи СОЛІД і справді є зловживанням інтерфейсами для цільових цілей.

Так, так, 50 методів - це запах, але це залежить від наміру і мети, поганий він чи ні. Це, звичайно, не ідеально.


0

У шарах доступу до даних, як правило, до одного класу додано багато методів. Якщо ви коли-небудь працювали з Entity Framework або іншими інструментами ORM, ви побачите, що вони генерують 100 методів. Я припускаю, що ви та ваш колега це вручну реалізуєте. Це не обов'язково кодовий запах, але це не дуже красиво. Не знаючи свого домену, важко сказати.


Методи чи властивості?
JeffO

0

Я використовую протоколи (називайте їх інтерфейсами, якщо хочете) майже універсально для всіх apis і з FP, і з OOP. (Пам'ятайте Матрицю? Конкресів немає!) Звичайно, існують конкретні типи, але в рамках програми кожен тип розглядається як щось, що грає роль у певному контексті.

Це означає, що об’єкти, передані протягом програм, у функції тощо, можна розглядати як абстрактні сутності з названими наборами поведінки. Об'єкт можна розглядати як роль, яка є деяким набором протоколів. Людина (конкретний тип) може бути людиною, батьком, чоловіком, другом і працівником, але я не уявляю багатьох функцій, які вважали б суб'єктом господарювання суму, що перевищує дві з них.

Напевно, можливо, що складний об'єкт міг дотримуватися декількох різних протоколів, але вам все одно буде важко натиснути на api з 50 методами. Більшість протоколів мають 1 або 2 способи, можливо 3, але ніколи 50! Будь-яка організація, яка має 50 методів, повинна скласти сукупність менших компонентів, кожен з яких має свої обов'язки. Суб'єкт господарювання взагалі представляє простіший інтерфейс, який відбирає загальну суму апісів всередині нього.

Замість того, щоб думати з точки зору предметів та методів, починайте мислити з абстракцій та контрактів та які ролі суб'єкта грає в якомусь контексті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.