Наследование против композиции для тестируемости
При проектировании своих объектов я считаю композицию лучшим выбором с точки зрения тестируемости. Причина в том, что я могу при необходимости выполнять макеты частей структуры композиции во время выполнения модульных тестов. Это невозможно, если у меня есть иерархия наследования.
Я хотел бы знать, нашли ли другие также, что это - причина, чтобы предпочесть состав. Кроме того, с какими еще трудностями при тестировании вы попали, потому что было использовано наследование?
6 ответов
Я считаю, что чем больше вы начинаете разрабатывать с использованием шаблонов проектирования, тем чаще и чаще вы будете находить, где композиция будет предпочтительнее наследования. Я действительно верю в книгу Head First: Design Patterns, что "Favor Composition Over Inheritance" является одним из основных принципов проектирования.
Ваш пример возможности макетировать части композиции для тестирования, возможно, является одним из лучших возможных примеров.
Редактировать: Хотя основной принцип в шаблонах проектирования - отдавать предпочтение композиции, а не наследованию, это не означает, что не существует шаблонов проектирования, которые используют наследование там, где это необходимо. Другим базовым примером является шаблон декоратора, где вы кодируете в сторону абстрактного суперкласса (хотя это для сопоставления типов, а не для реализации отношения "есть").
Это не ситуация или ситуация. Они не конкуренты.
Наследование также достаточно просто для модульного тестирования. Однако иногда для проверки абстрактного суперкласса требуются фиктивные конкретные классы.
Наследование может быть использовано неправильно. Некоторые проекты выглядят как ситуации "есть", но на самом деле это не так - они более тонкие. Иногда это действительно "ведет себя как", когда вам нужна какая-то композиция (например, стратегия), чтобы отделить поведение от других атрибутов.
Книга Gang of Four Design Patterns - это, в основном, книга о том, почему предпочтение композиции, а не наследование, и предлагает множество способов сделать это. Несколько причин:
классов увеличивает сложность кодовой базы
- Во многих новых языках наследование ограничено одним классом, в то время как вы можете составлять столько, сколько хотите
- Базовые классы не могут быть изменены во время выполнения (по сути, проблема, с которой вы сталкиваетесь).
Я думаю, что главная причина, по которой композицию проще тестировать, заключается в том, что наследование (реализация) имеет тенденцию создавать очень связанные классы, которые являются более хрупкими (Fragile Base Class) и которые сложнее тестировать изолированно.
Наследование определенно имеет свое применение, но я все чаще и чаще предпочитаю композицию наследованию.
"Композиция Favor Object над наследованием класса" на самом деле из книги GoF. Этот разговор с Эрихом Гаммой описывает эту идею из книги.
Одним важным шаблоном, который требует наследования, является шаблон шаблонного метода. Этот шаблон широко используется очень удобно, поэтому наследование здесь, чтобы остаться. Другим распространенным шаблоном, который использует наследование, является шаблон Composite. Суть, которую я пытаюсь подчеркнуть, заключается в том, что вообще не стоит сбрасывать со счетов наследование, но я надеюсь, что это все равно ясно, если взглянуть на столько распространенных API-интерфейсов...
Это зависит от контекста. Когда класс простой и наследование от простого общего класса (config/logger), тогда наследование выигрывает. Я в других случаях композицию в основном выигрываю