Можливо, ви щойно помічали людей, які говорять про це в останні кілька місяців, але хорошим програмістам це було відомо набагато довше. Я, безумовно, говорив про це десь десятиліття, де це доречно.
Сенс концепції полягає в тому, що в спадщині є великі концептуальні витрати. Коли ви використовуєте успадкування, то кожен виклик методу має в ньому неявну відправку. Якщо у вас є глибокі дерева спадкування, або багаторазове відправлення, або (що ще гірше) обоє, то з'ясування, куди конкретний метод буде відправлений у будь-якому конкретному дзвінку, може стати королівським ПДФА. Це робить правильні міркування про код складнішими, а налагодження стає важче.
Дозвольте навести простий приклад для ілюстрації. Припустимо, що глибоко у дереві спадкування хтось назвав метод foo
. Потім приходить хтось інший і додає foo
на верхівці дерева, але робить щось інше. (Цей випак частіше зустрічається з багатократним успадкуванням.) Тепер ця людина, що працює в кореневому класі, зламала незрозумілий дочірній клас і, мабуть, не усвідомлює цього. Ви можете мати 100% покриття одиничними тестами і не помітити цю поломку, оскільки людина вгорі не подумає про тестування дитячого класу, а тести для дочірнього класу не думають перевіряти нові методи, створені вгорі . (Правда, є способи написання одиничних тестів, які це сприймуть, але є також випадки, коли ви не можете легко написати тести таким чином.)
На противагу цьому, коли ви використовуєте склад, при кожному дзвінку зазвичай зрозуміліше, на що ви відправляєте дзвінок. (Гаразд, якщо ви використовуєте інверсію управління, наприклад, з введенням залежності, то з'ясування, куди йде виклик, також може стати проблематичним. Але зазвичай це простіше зрозуміти.) Це полегшує міркування про це. Як бонус, композиція призводить до того, що методи відокремлені один від одного. Наведений вище приклад не повинен відбуватися там, оскільки дочірній клас перейшов би на якийсь незрозумілий компонент, і ніколи не виникає питання про те, чи був виклик foo
призначений для незрозумілого компонента чи основного об'єкта.
Тепер ви абсолютно праві, що успадкування та склад - це два дуже різні інструменти, які служать двом різним типам речей. Впевнена спадщина несе концептуальні накладні витрати, але коли це правильний інструмент для роботи, вона має менше концептуальних витрат, ніж намагатися не використовувати її і робити вручну те, що вона робить для вас. Ніхто, хто знає, що вони роблять, не скаже, що ніколи не слід використовувати спадщину. Але будьте впевнені, що це правильно зробити.
На жаль, багато розробників дізнаються про об'єктно-орієнтоване програмне забезпечення, дізнаються про успадкування, а потім виходять, щоб якомога частіше використовувати свою нову сокиру. Що означає, що вони намагаються використовувати спадщину там, де композиція була правильним інструментом. Сподіваємось, вони вчасно навчаться краще, але часто це відбувається не після того, як кілька видалених кінцівок і т. Д. Повідомлення їм наперед, що це погана ідея, як правило, прискорює процес навчання і зменшує травми.