Які найбільш поширені шаблони проектування в Node.js?
Шаблони проектування в Node.js
Шаблони проектування — це повторно використовувані рішення для поширених проблем програмування. Node.js має кілька шаблонів, які особливо актуальні через свою асинхронну, подієву природу.
1. Шаблон модуля
Модулі Node.js забезпечують природну інкапсуляцію:
// counter.js — інкапсульований стан
let count = 0;
module.exports = {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
};const counter = require('./counter');
counter.increment();
console.log(counter.getCount()); // 12. Шаблон синглтона
Оскільки Node.js кешує require(), модулі природно є синглтонами:
// database.js
class Database {
constructor() {
if (Database.instance) return Database.instance;
this.connection = null;
Database.instance = this;
}
async connect(url) {
if (!this.connection) {
this.connection = await createConnection(url);
}
return this.connection;
}
}
module.exports = new Database();// Обидва повертають один і той же екземпляр
const db1 = require('./database');
const db2 = require('./database');
console.log(db1 === db2); // true3. Шаблон спостерігача (EventEmitter)
Основний елемент Node.js — широко використовується в потоках, HTTP та кастомних подіях:
const EventEmitter = require('events');
class OrderService extends EventEmitter {
placeOrder(order) {
// Бізнес-логіка...
this.emit('orderPlaced', order);
}
}
const orderService = new OrderService();
// Підписники
orderService.on('orderPlaced', (order) => {
emailService.sendConfirmation(order);
});
orderService.on('orderPlaced', (order) => {
inventoryService.updateStock(order);
});
orderService.placeOrder({ id: 1, item: 'Laptop' });4. Фабричний шаблон
Створення об'єктів без розкриття логіки створення:
class DatabaseFactory {
static create(type) {
switch (type) {
case 'postgres':
return new PostgresAdapter();
case 'mongodb':
return new MongoAdapter();
case 'redis':
return new RedisAdapter();
default:
throw new Error(`Невідомий тип бази даних: ${type}`);
}
}
}
const db = DatabaseFactory.create(process.env.DB_TYPE);5. Шаблон проміжного програмного забезпечення (Chain of Responsibility)
Основний шаблон в Express.js та NestJS:
class MiddlewareChain {
constructor() {
this.middlewares = [];
}
use(fn) {
this.middlewares.push(fn);
return this;
}
async execute(context) {
let index = 0;
const next = async () => {
if (index < this.middlewares.length) {
const middleware = this.middlewares[index++];
await middleware(context, next);
}
};
await next();
}
}
const chain = new MiddlewareChain();
chain.use(async (ctx, next) => {
console.log('Перевірка автентифікації');
ctx.user = { id: 1 };
await next();
});
chain.use(async (ctx, next) => {
console.log(`Користувач: ${ctx.user.id}`);
await next();
});6. Шаблон стратегії
Змінні алгоритми під час виконання:
class PaymentProcessor {
constructor(strategy) {
this.strategy = strategy;
}
async pay(amount) {
return this.strategy.process(amount);
}
}
const stripeStrategy = {
process: (amount) => stripe.charges.create({ amount })
};
const paypalStrategy = {
process: (amount) => paypal.payment.create({ amount })
};
// Використання Stripe
const processor = new PaymentProcessor(stripeStrategy);
await processor.pay(100);7. Шаблон репозиторію
Абстрагує доступ до даних від бізнес-логіки:
class UserRepository {
constructor(database) {
this.db = database;
}
async findById(id) {
return this.db.query('SELECT * FROM users WHERE id = $1', [id]);
}
async create(userData) {
return this.db.query(
'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
[userData.name, userData.email]
);
}
async findByEmail(email) {
return this.db.query('SELECT * FROM users WHERE email = $1', [email]);
}
}Підсумок шаблонів
| Шаблон | Використання в Node.js |
|---|---|
| Модуль | Інкапсуляція, організація коду |
| Синглтон | З'єднання з БД, конфігурація, кеші |
| Спостерігач | Подієва комунікація |
| Фабрика | Абстракція створення об'єктів |
| Проміжне ПЗ | Пайплайни обробки запитів |
| Стратегія | Змінні алгоритми |
| Репозиторій | Абстракція доступу до даних |
| Декоратор | Розширення поведінки (NestJS) |
| Проксі | Кешування, логування, контроль доступу |
Порада: Не намагайтеся нав'язувати шаблони, де вони не підходять. Система модулів Node.js та подієва природа вже сприяють чистим шаблонам. Використовуйте їх, коли вони вирішують реальні проблеми, а не для теоретичної чистоти.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.