Factory паттерн для компонентов

Фабричный паттерн в контексте Vue.js применяется для централизованного и предсказуемого создания компонентов. Вместо прямого импорта и регистрации каждого компонента используется функция-фабрика, которая инкапсулирует логику выбора, конфигурации и возврата компонента. Такой подход особенно актуален в приложениях со сложной структурой интерфейса, динамическими сценариями и большим количеством однотипных компонентов.

Ключевая особенность — отделение логики создания компонента от места его использования.


Базовая фабрика компонентов

Простейшая фабрика представляет собой функцию, возвращающую компонент в зависимости от входных параметров.

import TextInput from '@/components/inputs/TextInput.vue'
import NumberInput from '@/components/inputs/NumberInput.vue'
import DateInput from '@/components/inputs/DateInput.vue'

export function inputFactory(type) {
  switch (type) {
    case 'text':
      return TextInput
    case 'number':
      return NumberInput
    case 'date':
      return DateInput
    default:
      return null
  }
}

Использование фабрики в шаблоне через динамический компонент:

<component :is="currentInputComponent" />
import { inputFactory } from '@/factories/inputFactory'

export default {
  props: {
    type: String
  },
  computed: {
    currentInputComponent() {
      return inputFactory(this.type)
    }
  }
}

Регистрация компонентов через фабрику

Фабрика может не только возвращать компонент, но и выполнять его регистрацию. Это удобно при использовании глобальных компонентов или плагинов.

import TextInput from '@/components/inputs/TextInput.vue'
import NumberInput from '@/components/inputs/NumberInput.vue'

const registry = {
  text: TextInput,
  number: NumberInput
}

export function registerInputs(app) {
  Object.entries(registry).forEach(([name, component]) => {
    app.component(`Input${name}`, component)
  })
}

Такой подход упрощает контроль над пространством имён и исключает дублирование кода регистрации.


Фабрика с конфигурацией и параметрами

Фабричный паттерн раскрывается сильнее при добавлении конфигурации. Фабрика может возвращать не просто компонент, а обёрнутый компонент с заранее заданными свойствами.

import BaseButton from '@/components/BaseButton.vue'

export function buttonFactory(options) {
  return {
    extends: BaseButton,
    props: {
      ...BaseButton.props,
      variant: {
        type: String,
        default: options.variant
      }
    }
  }
}

Использование:

const PrimaryButton = buttonFactory({ variant: 'primary' })
const DangerButton = buttonFactory({ variant: 'danger' })

В результате создаются разные компоненты на базе одного шаблона без дублирования.


Фабрика для асинхронных компонентов

Vue поддерживает асинхронную загрузку компонентов, и фабрика позволяет централизовать этот механизм.

export function asyncComponentFactory(loader) {
  return () => ({
    component: loader(),
    delay: 200,
    timeout: 3000
  })
}

Пример использования:

const UserCard = asyncComponentFactory(() =>
  import('@/components/UserCard.vue')
)

Преимущество — единые правила загрузки, таймаутов и обработки ошибок.


Связь фабрики с бизнес-логикой

Фабрика может учитывать состояние приложения, роли пользователя или данные с сервера.

import AdminPanel from '@/components/AdminPanel.vue'
import UserPanel from '@/components/UserPanel.vue'

export function panelFactory(role) {
  if (role === 'admin') {
    return AdminPanel
  }
  return UserPanel
}

В данном случае компонент становится результатом бизнес-решения, а не просто отображением.


Фабрика и слоты

Фабричный компонент может заранее определять структуру слотов.

export function layoutFactory(headerComponent, footerComponent) {
  return {
    components: { headerComponent, footerComponent },
    template: `
      <div class="layout">
        <headerComponent />
        <slot />
        <footerComponent />
      </div>
    `
  }
}

Это позволяет формировать разные макеты на основе одной фабрики без жёсткой привязки к конкретным компонентам.


Сравнение с альтернативными подходами

Прямой импорт компонентов

  • жёсткая связанность
  • сложнее масштабировать
  • больше условной логики в шаблонах

Фабричный паттерн

  • единая точка изменения
  • уменьшение условных конструкций
  • удобство при динамической архитектуре

Типизация фабрик (Vue + TypeScript)

При использовании TypeScript фабрика может возвращать строго типизированные компоненты.

import { DefineComponent } from 'vue'
import TextInput from '@/components/inputs/TextInput.vue'

export function typedFactory(): DefineComponent {
  return TextInput
}

Типизация снижает количество ошибок при работе с динамическими компонентами и улучшает автодополнение.


Архитектурные рекомендации

  • фабрики размещаются отдельно от компонентов (/factories)
  • одна фабрика — одна ответственность
  • фабрика не должна знать о DOM или маршрутах
  • логика выбора должна быть детерминированной

Когда фабричный паттерн особенно полезен

  • динамические формы
  • визуальные конструкторы
  • CMS-подобные интерфейсы
  • сложные дизайн-системы
  • плагины и расширяемые модули

Фабричный паттерн в Vue.js усиливает модульность, упрощает сопровождение и позволяет строить масштабируемую архитектуру компонентов без избыточной связности.