1. Singleton Pattern
What is it?
A design pattern that restricts the instantiation of a class to a single instance.
When was it created?
Introduced as part of the GoF (Gang of Four) design patterns in 1994.
Node.js Support:
All versions of Node.js.
Why use it?
Prevents multiple instances and manages global state efficiently.
Best Practices:
• Use it for shared configurations or resource-heavy classes.
Example:
class Singleton {
static instance;
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}
const singletonA = new Singleton();
const singletonB = new Singleton();
console.log(singletonA === singletonB); // true
Pros:
• Global access point.
• Easy to manage shared state.
Cons:
• Harder to test and refactor due to global reliance.
2. Factory Pattern
What is it?
Encapsulates object creation logic, returning objects from a shared interface.
When was it created?
Another GoF pattern from the 1990s.
Node.js Support:
Supported across all versions.
Why use it?
Simplifies complex object creation.
Best Practices:
• Useful when dealing with large-scale applications needing multiple object types.
Example:
class Car {
constructor(model) { this.model = model; }
}
class CarFactory {
createCar(type) {
switch(type) {
case 'sedan': return new Car('Sedan');
case 'suv': return new Car('SUV');
default: return null;
}
}
}
const factory = new CarFactory();
const sedan = factory.createCar('sedan');
console.log(sedan.model); // 'Sedan'
Pros:
• Encapsulates object creation logic.
• Supports easy object extension.
Cons:
• Overhead for simple objects.
3. Observer Pattern
What is it?
Allows one object (subject) to notify observers about state changes.
When was it created?
First formalized in the 1970s; adopted into JS in event-driven systems.
Node.js Support:
Supported by event-driven architecture.
Why use it?
Ideal for decoupling objects in event-based systems.
Best Practices:
• Use it in pub/sub messaging systems.
Example:
class Observer {
update(data) { console.log(`Observer received: ${data}`); }
}
class Subject {
constructor() { this.observers = []; }
addObserver(observer) { this.observers.push(observer); }
notify(data) { this.observers.forEach(o => o.update(data)); }
}
const subject = new Subject();
const observer = new Observer();
subject.addObserver(observer);
subject.notify('Event Fired'); // Observer received: Event Fired
Pros:
• Promotes loose coupling.
Cons:
• Can be complex to manage with many observers.
4. Strategy Pattern
What is it?
Encapsulates algorithms and allows them to be interchangeable within a class.
When was it created?
Part of GoF’s 1994 design patterns.
Node.js Support:
Supported in all modern versions.
Why use it?
Allows flexibility by changing algorithms dynamically.
Best Practices:
• Ideal for scenarios requiring multiple approaches to the same problem.
Example:
class Context {
setStrategy(strategy) { this.strategy = strategy; }
executeStrategy(a, b) { return this.strategy.doOperation(a, b); }
}
class Add {
doOperation(a, b) { return a + b; }
}
class Subtract {
doOperation(a, b) { return a - b; }
}
const context = new Context();
context.setStrategy(new Add());
console.log(context.executeStrategy(5, 3)); // 8
context.setStrategy(new Subtract());
console.log(context.executeStrategy(5, 3)); // 2
Pros:
• Easy to switch algorithms.
Cons:
• Increases class complexity.
5. Decorator Pattern
What is it?
Dynamically adds responsibilities to objects.
When was it created?
From GoF’s pattern library.
Node.js Support:
Supported in all versions with ES6 classes.
Why use it?
Provides flexible object functionality without subclassing.
Best Practices:
• Use it for adding extra features or responsibilities to objects.
Example:
class Car {
getDescription() { return 'Car'; }
}
class SportsCarDecorator {
constructor(car) { this.car = car; }
getDescription() { return `${this.car.getDescription()} with sports package`; }
}
const car = new Car();
const sportsCar = new SportsCarDecorator(car);
console.log(sportsCar.getDescription()); // 'Car with sports package'
Pros:
• Extends functionality dynamically.
Cons:
• Can make the code harder to read if overused.