Advanced Node.js Design Patterns
Learn essential design patterns for Node.js applications including Singleton, Factory, Observer, and Module patterns. This is a foundational concept in server-side JavaScript development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Node.js experience. Take your time with each section and practice the examples
Singleton Pattern
Ensure a class has only one instance and provide global access to it.. This is an essential concept that every Node.js developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Factory Pattern
// Factory pattern for creating objects
class DatabaseConnectionFactory {
static createConnection(type) {
switch (type) {
case 'mysql':
return new MySQLConnection();
case 'postgresql':
return new PostgreSQLConnection();
case 'mongodb':
return new MongoDBConnection();
default:
throw new Error('Unsupported database type');
}
}
}
class MySQLConnection {
connect() {
console.log('Connecting to MySQL');
}
}
class PostgreSQLConnection {
connect() {
console.log('Connecting to PostgreSQL');
}
}
// Usage
const db = DatabaseConnectionFactory.createConnection('mysql');
db.connect();Observer Pattern
// Event-driven architecture with Observer pattern
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(listener => listener(data));
}
}
}
// Usage
const emitter = new EventEmitter();
emitter.on('user:created', (user) => {
console.log('User created:', user);
});
emitter.emit('user:created', { id: 1, name: 'John' });Module Pattern
// Module pattern for encapsulation
const UserModule = (() => {
let users = [];
return {
addUser: (user) => {
users.push(user);
},
getUsers: () => [...users],
getUserById: (id) => users.find(u => u.id === id)
};
})();
// Usage
UserModule.addUser({ id: 1, name: 'John' });
console.log(UserModule.getUsers());strategy Pattern
// strategy pattern for different algorithms
class PaymentProcessor {
constructor(strategy) {
this.strategy = strategy;
}
processPayment(amount) {
return this.strategy.process(amount);
}
}
class CreditCardStrategy {
process(amount) {
return `Processing ${amount} via Credit Card`;
}
}
class PayPalStrategy {
process(amount) {
return `Processing ${amount} via PayPal`;
}
}
// Usage
const processor = new PaymentProcessor(new CreditCardStrategy());
console.log(processor.processPayment(100));Mini-Project: Complete Pattern Implementation
// Complete design patterns implementation
class Logger {
constructor() {
if (Logger.instance) {
return Logger.instance;
}
this.logs = [];
Logger.instance = this;
}
log(message) {
const timestamp = new Date().toISOString();
this.logs.push({ message, timestamp });
console.log(`[${timestamp}] ${message}`);
}
getLogs() {
return this.logs;
}
}
// Factory for different types of handlers
class HandlerFactory {
static createHandler(type) {
switch (type) {
case 'email':
return new EmailHandler();
case 'sms':
return new SMSHandler();
case 'push':
return new PushHandler();
default:
throw new Error('Unknown handler type');
}
}
}
class EmailHandler {
send(message) {
console.log(`Sending email: ${message}`);
}
}
class SMSHandler {
send(message) {
console.log(`Sending SMS: ${message}`);
}
}
// Observer pattern for notifications
class NotificationService {
constructor() {
this.subscribers = [];
}
subscribe(callback) {
this.subscribers.push(callback);
}
notify(data) {
this.subscribers.forEach(callback => callback(data));
}
}
// Usage
const logger = new Logger();
const notificationService = new NotificationService();
notificationService.subscribe((data) => {
logger.log(`Notification sent: ${data.message}`);
});
const emailHandler = HandlerFactory.createHandler('email');
emailHandler.send('Welcome to our service!');