Композиция вместо наследования

↑ 8.1 Парадигмы: ООП, ФП, SOLID · ← Предыдущая · → Следующая

Желательно~3 мин чтенияУровень: senior

Зачем это на собесе

Ключевой принцип проектирования: спрашивают, чем композиция лучше и как это выглядит во Vue.

Проблема наследования

  • жёсткая связь подкласса с реализацией родителя;
  • комбинаторный взрыв классов (AdminUserWithAudit, GuestUserWithCache);
  • нельзя унаследовать сразу от нескольких;
  • изменения в базовом классе ломают всех потомков.

Композиция

Собираем поведение из небольших независимых частей.

// вместо class ExportableSortableTable extends Table
const useSort = <T>(items: Ref<T[]>) => { /* ... */ }
const useExport = <T>(items: Ref<T[]>) => { /* ... */ }
const usePaging = <T>(items: Ref<T[]>) => { /* ... */ }
 
function useTable<T>(source: Ref<T[]>) {
  const sorted = useSort(source)
  const paged = usePaging(sorted.items)
  const exporter = useExport(paged.pageItems)
  return { ...sorted, ...paged, ...exporter }
}

Композиция во Vue

МеханизмЧто композирует
Composablesлогика с состоянием
Slotsразметка
Props / eventsконтракт компонента
provide / injectзависимости через дерево
Директивы, pluginsсквозное поведение

Замена mixins: они давали конфликты имён и неявные источники данных, composables явные.

Когда наследование оправдано

Устойчивая иерархия «является» (is-a) с общими инвариантами, а не переиспользование кода. Ещё вариант — базовые классы фреймворка (например HTMLElement для Web Components).

Практика

  • используйте небольшие интерфейсы и функции;
  • зависимость через параметр, а не через наследование;
  • decorator, strategy, adapter — паттерны композиции.

Вопросы с ответами