Коли використовувати риси, на відміну від успадкування та складу?


9

Існує три поширених способи - AFAIK - реалізувати повторне використання, коли мова йде про OOP

  1. Спадщина: зазвичай представляти є - відносини (качка - птах)
  2. Склад: зазвичай представляють стосунки (автомобіль має двигун)
  3. Риси (наприклад, ключове слово trait у PHP): ... не дуже впевнений у цьому

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


Ви можете пояснити трохи більше про риси, але чи можуть риси бути просто іншим словом для композицій?
Триларіон


1
Мені б дуже хотілося знати, чому також. Не використовував їх жодного разу.
Енді

Відповіді:


6

Риси - це ще один спосіб складання композиції. Подумайте про них як про спосіб складання всіх частин класу під час компіляції (або часу компіляції JIT), складання конкретних реалізацій частин, які вам знадобляться.

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

class TestMyClass
  extends WordSpecLike
  with Matchers
  with MyCustomTrait
  with BeforeAndAfterAll
  with BeforeAndAfterEach
  with ScalaFutures

Розділ рамки випробувань мають масу різних варіантів конфігурації, і кожна команда має різні переваги про те , як вони хочуть , щоб робити речі. withВстановлюючи параметри в риси (які змішуються при використанні в Scala), ScalaTest може запропонувати всі ці варіанти, не створюючи назви класів, як WordSpecLikeWithMatchersAndFutures, або тонни булевих прапорів виконання WordSpecLike(enableFutures, enableMatchers, ...). Це дозволяє легко дотримуватися принципу відкритого / закритого типу . Ви можете додавати нові функції та нові комбінації функцій, просто додаючи нову ознаку. Це також полегшує дотримання принципу поділу інтерфейсу , оскільки ви можете легко помістити функції, які не є загально необхідними, у ознаку.

Риси також є хорошим способом розміщення загального коду на кілька класів, які не мають сенсу розділяти ієрархію спадкування. Спадщина - це дуже тісно пов'язані відносини, і ви не повинні платити ці витрати, якщо зможете в цьому допомогти. Риси - це набагато більш вільно пов'язані відносини. У своєму прикладі вище я використовував, MyCustomTraitщоб легко поділитись реалізацією макетної бази даних між декількома інакше не пов'язаними тестовими класами.

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

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


Привіт, це чудова відповідь. Чи можу я запитати, як вирішувати, коли використовувати ознаки та коли використовувати ін'єкцію залежності? яка, здається, досягає того ж.
Екстракун

Проникливі спостереження. Дивіться мою редакцію.
Карл Білефельдт

Дякуємо, що написали це. Мені цікаво Ваша відповідь про такі риси, як композиція @KarlBielefeldt. Ваш клас можна використовувати там, де потрібна ця ознака, і ви все одно будете страждати від тієї ж крихкості, як і у звичайному інтерфейсі. Тож це здається ближчим до підтипу та успадкування, ні? Я також не впевнений, наскільки це схоже на DI ... якщо у вас визначені різні класи, які розширюють ознаки, то чи не визначені ті конкретні залежності, де б в ієрархії цей клас не був визначений, а не у верхній / вхідній точці код? Дякую!
allstar

Риси можна використовувати так само, як інтерфейси, для їх спадкових властивостей, але це не те, що робить їх унікальними. withОператор , що відрізняє їх, і withє операцією композиції. І так, риси замінюють DI, не потребуючи визначення в точці введення коду. Це одна з речей, яка робить їх кращими на мою думку.
Карл Білефельдт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.