Ответ
В разработке на Node.js я активно применяю следующие паттерны:
-
Middleware / Chain of Responsibility: Основа большинства веб-фреймворков (Express, Koa). Позволяет декомпозировать обработку запроса.
// Express middleware для логирования и аутентификации const logger = (req, res, next) => { console.log(`${req.method} ${req.url}`); next(); }; const auth = (req, res, next) => { const token = req.headers.authorization; if (!isValidToken(token)) return res.status(401).send('Unauthorized'); req.user = decodeToken(token); next(); }; app.use(logger); app.use('/api', auth); // Применяется только к маршрутам /api/* -
Repository / Data Mapper: Для абстракции работы с базой данных. Бизнес-логика работает с "репозиториями", а не с конкретными ORM-запросами.
// user.repository.js class UserRepository { constructor(model) { this.model = model; } async findById(id) { return this.model.findById(id); } async findByEmail(email) { return this.model.findOne({ email }); } } // В сервисе const userRepo = new UserRepository(UserModel); const user = await userRepo.findByEmail('test@example.com'); -
Dependency Injection (DI): Улучшает тестируемость. Вместо жёсткого импорта модулей, зависимости передаются в конструктор или функцию.
// Сервис, принимающий репозиторий как зависимость class UserService { constructor(userRepository, emailService) { this.userRepo = userRepository; this.emailService = emailService; } async register(userData) { const user = await this.userRepo.create(userData); await this.emailService.sendWelcomeEmail(user.email); return user; } } // В тестах легко подменить репозиторий на mock -
Factory: Для создания сложных объектов, например, разных типов подключений или валидаторов.
function createDatabaseConnection(type) { if (type === 'mongodb') return new MongoClient(uri); if (type === 'redis') return new RedisClient(); throw new Error(`Unsupported DB type: ${type}`); } const db = createDatabaseConnection(process.env.DB_TYPE); -
Observer / Event Emitter: Встроен в Node.js через класс
EventEmitter. Используется для организации слабосвязанной коммуникации между частями приложения.const EventEmitter = require('events'); class OrderService extends EventEmitter { async processOrder(order) { // ... логика обработки this.emit('order.processed', { orderId: order.id }); } } const orderService = new OrderService(); orderService.on('order.processed', (data) => { // Отправить уведомление, обновить кэш и т.д. console.log(`Order ${data.orderId} processed`); }); -
Module Pattern / Singleton (через кэш модулей CommonJS): Node.js сам реализует Singleton для модулей. При первом
require()модуль кэшируется, и последующие вызовы возвращают тот же экземпляр.
Эти паттерны помогают создавать поддерживаемые, тестируемые и масштабируемые приложения на Node.js.