JavaScript Design Patterns: Explained with Examples
What Are Design Patterns?
Design patterns are reusable solutions to common programming problems. They help you write clean, maintainable, and scalable JavaScript code by following time-tested architecture.
Types of JavaScript Design Patterns
1. Creational Patterns – For creating objects
2. Structural Patterns – For organizing code and relationships
3. Behavioral Patterns – For communication between objects
1. Creational Patterns
a) Constructor Pattern
Used to create multiple instances of an object with the same structure.
function Person(name, age) {
this.name = name;
this.age = age;
}
const person1 = new Person("Alice", 25);
Use case: Creating similar objects efficiently.
b) Factory Pattern
Creates objects without specifying the exact class.
function createUser(role) {
if (role === "admin") {
return { role, permissions: "all" };
} else {
return { role, permissions: "limited" };
}
}
const admin = createUser("admin");
Use case: When object creation needs to be flexible.
c) Singleton Pattern
Restricts instantiation to one object only.
const Singleton = (function () {
let instance;
function createInstance() {
return { id: Date.now() };
}
return {
getInstance: function () {
if (!instance) instance = createInstance();
return instance;
},
};
})();
const obj1 = Singleton.getInstance();
const obj2 = Singleton.getInstance();
console.log(obj1 === obj2); // true
Use case: Managing shared resources (e.g., DB connection).
2. Structural Patterns
a) Module Pattern
Encapsulates private variables/functions.
const CounterModule = (function () {
let count = 0;
return {
increment() {
count++;
console.log(count);
},
reset() {
count = 0;
},
};
})();
CounterModule.increment(); // 1
CounterModule.increment(); // 2
Use case: Data privacy and encapsulation.
b) Decorator Pattern
Adds new functionality to existing objects.
function vehicle() {
this.drive = () => console.log("Driving");
}
function turbo(vehicle) {
vehicle.turboBoost = () => console.log("Turbo Mode");
return vehicle;
}
const car = turbo(new vehicle());
car.drive(); // Driving
car.turboBoost(); // Turbo Mode
Use case: Enhancing object functionality.
3. Behavioral Patterns
a) Observer Pattern
When one object (subject) updates, observers are notified.
class Subject {
constructor() {
this.observers = [];
}
subscribe(fn) {
this.observers.push(fn);
}
notify(data) {
this.observers.forEach((fn) => fn(data));
}
}
const news = new Subject();
news.subscribe((data) => console.log("News Update:"
, data));
news.notify("New article published");
Use case: Reactivity systems, pub/sub (e.g., event handling).
b) Command Pattern
Encapsulates a request as an object.
function lightOn() {
console.log("Light turned ON");
}
function lightOff() {
console.log("Light turned OFF");
}
function execute(fn) {
fn();
}
execute(lightOn); // Light turned ON
Use case: Queued commands, undo/redo functionality.
c) Strategy Pattern
Defines different algorithms as interchangeable objects.
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
function calculate(a, b, strategy) {
return strategy(a, b);
}
console.log(calculate(10, 5, add)); // 15
console.log(calculate(10, 5, subtract)); // 5
Use case: Switching between multiple strategies dynamically.
Summary Table
Pattern Type | Pattern | Use Case Example |
---|---|---|
Creational | Singleton | Logging system, DB connection |
Creational | Factory | UI components |
Structural | Module | Encapsulation, private data |
Structural | Decorator | Add methods to an object |
Behavioral | Observer | Event listeners, pub/sub |
Behavioral | Strategy | Dynamic algorithm switching |