> Какие паттерны проектирования вы знаете и использовали в работе (JavaScript)
Уровень: senior · Роль: frontend · Язык: JavaScript · Категория: Технические вопросы
Компании: Mosline
Стек: Node.js, JavaScript
> Пример ответа
Короткий ответ
В работе я активно использовал порождающие, структурные и поведенческие паттерны. Из порождающих - Singleton для глобального состояния и Factory для создания сложных объектов. Из структурных - Module, Proxy (для кэширования API-запросов) и Decorator (для middleware в Express). Из поведенческих - Observer (EventEmitter в Node.js), Strategy (для переключения алгоритмов валидации) и Command (для отмены действий в редакторе). Также применял паттерн Container/DI для управления зависимостями.
Подробное объяснение
Паттерны проектирования - это проверенные решения типовых задач, которые возникают при разработке ПО. В контексте JavaScript и Node.js они особенно важны из-за асинхронной природы языка и особенностей прототипного наследования.
Порождающие паттерны управляют процессом создания объектов:
- Singleton - гарантирует единственный экземпляр класса. В Node.js модули кэшируются, поэтому каждый модуль по умолчанию является синглтоном.
- Factory - инкапсулирует логику создания объектов, что полезно при сложной инициализации или условном выборе реализации.
- Builder - удобен для конструирования объектов с множеством опциональных параметров.
Структурные паттерны определяют отношения между объектами:
- Module - основа организации кода в JS, инкапсулирует приватные данные через замыкания.
- Proxy - контролирует доступ к объекту, часто используется для кэширования, логирования или ленивой инициализации.
- Decorator - динамически добавляет поведение объекту. В Node.js это основа middleware-пайплайнов.
- Adapter - преобразует интерфейс одного класса в интерфейс, ожидаемый клиентом.
Поведенческие паттерны управляют взаимодействием между объектами:
- Observer - реализует механизм подписки и уведомления. EventEmitter в Node.js - классическая реализация.
- Strategy - позволяет менять алгоритм на лету, выделяя его в отдельный класс.
- Command - инкапсулирует запрос как объект, что даёт возможность откладывать выполнение, логировать или отменять действия.
- Middleware - цепочка обработчиков, где каждый может прервать или модифицировать запрос.
На практике
В реальных проектах я редко использую паттерны формально - скорее, они возникают естественно как реакция на конкретные проблемы.
Singleton применял для конфигурации приложения и подключения к базе данных. В Node.js это тривиально: module.exports = new Database().
Factory использовал при создании различных типов парсеров для импорта данных - в зависимости от формата файла (CSV, JSON, XML) фабрика возвращала нужный парсер.
Proxy реализовал для кэширования ответов внешнего API. Прокси-объект проверял, есть ли данные в кэше, и только при промахе обращался к реальному API.
Observer - основа event-driven архитектуры в Node.js. Использовал EventEmitter для системы уведомлений: когда пользователь совершал действие, эмиттер оповещал подписанные сервисы (логирование, отправка email, обновление кэша).
Strategy применял для валидации форм на фронтенде. Каждое правило валидации (required, email, minLength) - отдельная стратегия, которая комбинировалась в цепочку.
Command - в редакторе текста для реализации undo/redo. Каждое действие (вставка, удаление) оборачивалось в команду с методами execute и undo.
Middleware - основа Express и Koa. Каждый middleware - это декоратор, который может модифицировать request/response или прервать цепочку.
Пример кода
JAVASCRIPT// Пример паттерна Strategy для валидацииclass ValidationStrategy {validate(value) { throw new Error('Not implemented'); }}class RequiredStrategy extends ValidationStrategy {validate(value) {return value !== undefined && value !== null && value !== '';}}class EmailStrategy extends ValidationStrategy {validate(value) {return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);}}class MinLengthStrategy extends ValidationStrategy {constructor(min) {super();this.min = min;}validate(value) {return typeof value === 'string' && value.length >= this.min;}}class Validator {constructor() {this.strategies = [];}addStrategy(strategy) {this.strategies.push(strategy);}validate(value) {return this.strategies.every(s => s.validate(value));}}// Использованиеconst validator = new Validator();validator.addStrategy(new RequiredStrategy());validator.addStrategy(new MinLengthStrategy(3));console.log(validator.validate('ab')); // falseconsole.log(validator.validate('abc')); // true
Как отвечать на собеседовании
Начните с краткого перечисления основных групп паттернов и приведите 1-2 примера из каждой. Затем выберите один паттерн и подробно объясните, какую проблему он решал в вашем проекте. Важно не просто назвать паттерны, а показать понимание trade-off: когда паттерн полезен, а когда избыточен.
Хорошо упомянуть, что в JavaScript некоторые паттерны реализуются нативно (Module через модули ES, Singleton через кэширование модулей Node.js, Observer через EventEmitter). Это показывает глубокое понимание языка.
Избегайте перечисления всех паттернов подряд - это выглядит как заученный список. Лучше 3-4 паттерна с конкретными примерами из практики.
Что проверяет интервьюер
Интервьюер оценивает:
- Понимание не просто названий, а сути паттернов - какую проблему они решают и какие компромиссы несут.
- Умение применять паттерны в контексте JavaScript/Node.js, а не абстрактно из книг GoF.
- Способность выбирать правильный паттерн под задачу, а не использовать все подряд.
- Понимание, что паттерны - это инструменты, а не догмы. Иногда проще написать функцию, чем реализовывать полноценный паттерн.
Типичные ошибки
- Перечисление всех паттернов из книги GoF без привязки к реальному опыту.
- Попытка втиснуть паттерн туда, где он не нужен (overengineering).
- Путаница между паттернами и архитектурными стилями (например, MVC - это архитектурный паттерн, а не паттерн проектирования).
- Непонимание, что в JavaScript многие паттерны реализуются проще из-за first-class functions и динамической типизации.
- Игнорирование нативных реализаций: например, предлагать реализовать Observer вручную, когда EventEmitter уже есть в Node.js.
> Похожие задачи по JavaScript
Какой опыт работы с REST API и какими инструментами пользовалась
Что такое принципы SOLID и как они помогают писать структурированный код
Что такое GiST индекс и как он устроен
Какие типы индексов кроме B-tree существуют и используются
> Похожие задачи по frontend
Какой опыт работы с REST API и какими инструментами пользовалась
Что такое принципы SOLID и как они помогают писать структурированный код
Что такое GiST индекс и как он устроен
Какие типы индексов кроме B-tree существуют и используются
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью