Як ми знаємо, що користь композиції над узагальненням завжди є правильним вибором?


9

Будь-який об'єкт фізично існує чи ні, ми можемо вибрати його моделювати різними способами. Ми могли б довільно використовувати узагальнення чи склад у багатьох випадках. Однак принцип GoF "користь композиції над узагальненням [sic]" керує нами використанням композиції. Отже, коли ми моделюємо, наприклад, рядок, тоді ми створюємо клас, який містить два члени PointA і PointB типу Point (композиція) замість розширення Point (узагальнення). Це лише спрощений приклад того, як ми можемо довільно обирати склад або спадщину для моделювання, незважаючи на те, що об'єкти зазвичай набагато складніші.

Як ми можемо знати, що це правильний вибір? Це має значення хоча б тому, що може бути зроблено багато рефакторингу, якщо це неправильно?


9
Ваш приклад насправді не працює, тому що ви не можете сказати, що рядок є крапкою, і тому він не відповідає Принципу заміни Ліскова і успадкування не підходить.
Дін Гардінг

@Dean: Як ви, напевно, знаєте, приклад не є головним. Для запису лінію можна представити у вигляді рівняння, визначеного через дві точки.
CarneyCode


1
@Songo: Здається, ви зовсім пропустили справу.
CarneyCode

Чи не розширення спеціалізації замість узагальнення?
Тулен Кордова

Відповіді:


17

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

Звідки ми це знаємо? З досвіду та досвіду інших.

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

Але моїх анекдотичних доказів повинно бути недостатньо. Подивіться по Інтернету, і хороша кількість людей пережили той самий досвід.


Мені подобається; взяти нагороду.
CarneyCode

+1 за "Я ніколи не бачив ситуації, коли композиційна структура потребувала б рефакторингу у спадщину".
Казарк

7

Якщо ви хочете більш чіткого правила, що перевищує "користь композиції над спадщиною", я можу запропонувати щось подібне:

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

Однак, як і всі великі правила, як тільки ви зрозумієте правило - тоді ви можете порушити правило :)


0

Я не бачу, як композиція та узагальнення є альтернативними, і не вдалося знайти цитату .
Склад і успадкування (для досягнення спеціалізації), і можна стверджувати, що абстрагування та узагальнення є (для досягнення модульності).

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


Це природніше? Рядок - це не більше двох точок, ніж це одна точка, розширена?
CarneyCode

2
Я ніколи не бачив визначення рядка, яке не передбачає того, що воно складається з 2+ балів. Навіть використовуючи рівняння рядка, якщо у вашому домені чисел є лише значення 1 x, то це точка, а не лінія.
Ріг

0

Перевага відбувається тоді, коли обидва кандидати мають право. Проблема, викладена у запитанні, не спрацьовує в цьому обліковому записі, оскільки вона має лише варіант композиції.

"Композиція також може використовувати узагальнення". Чи має це твердження для нас сенс? Якщо ні, то ми ще не готові зрозуміти правило «прихильності».

Чому ми надаємо перевагу композиції, це те, що Композиція пропонує більше можливостей розширення / гнучкості, ніж узагальнення. Це розширення / гнучкість стосується переважно гнучкості виконання / динаміки (що досягається комбінацією інтерфейсів та композиції).

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

Короткий зміст: Склад: З'єднання зменшується лише наявністю дрібних речей, які ви підключаєте до чогось більшого, а більший об'єкт просто викликає менший об'єкт назад. Генералізація: З точки зору API стороннього виробника, що визначає, що метод може бути відмінено, є більш сильним зобов'язанням, ніж визначення того, що метод можна викликати (впевнений виграш для Генералізації). І ніколи не забувайте, що для композиції ви також використовуєте генералізацію із інтерфейсу замість великого класу. Але вся заслуга, на жаль, припадає на склад.


-4

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

Якщо абстракція продиктована 3d партією api - зазвичай правильно використовувати спадщину. У вітчизняному дизайні сутність повинна бути або абстрактною, або запечатаною. Абстрактна сутність потенційно повинна мати близько 3 спадкоємців. Мені не подобаються точки розширення одного віртуального методу. Все вище - про мій смак. Я не говорю про абстракцію інтерфейсу, яка є цілком різною історією.

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