Understanding Modern Design Patterns in JavaScript
Introduction
Design patterns are reusable solutions to common problems encountered in software design. They aren't templates or blueprints—rather, they offer guidelines on how to structure code to solve certain problems. This article explores modern design patterns commonly used in JavaScript, offering practical examples and recommending resources for deeper understanding.
Singleton Pattern
Overview
The Singleton pattern restricts a class from instantiating multiple objects. It is used in scenarios where a single instance of a class controls access to a resource, like a database or a file.
Learn More About Singleton PatternExample
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // Output: true
Factory Method Pattern
Overview
The Factory Method is a creational pattern providing an interface for creating objects but allowing subclasses to alter the type of objects that will be created.
Learn More About Factory Method PatternExample
class CarFactory {
createCar(type) {
if (type === "Sedan") {
return new Sedan();
} else if (type === "SUV") {
return new SUV();
}
}
}
class Sedan {
constructor() {
this.type = "Sedan";
}
}
class SUV {
constructor() {
this.type = "SUV";
}
}
const factory = new CarFactory();
const mySedan = factory.createCar("Sedan");
console.log(mySedan.type); // Output: Sedan
Observer Pattern
Overview
The Observer pattern offers a subscription model where objects subscribe to an event and get notified when the event occurs. This pattern is commonly used in distributed event handling systems.
Learn More About Observer PatternExample
class Observer {
constructor() {
this.observers = [];
}
subscribe(fn) {
this.observers.push(fn);
}
unsubscribe(fn) {
this.observers = this.observers.filter(subscriber => subscriber !== fn);
}
notify(data) {
this.observers.forEach(observer => observer(data));
}
}
const obs = new Observer();
obs.subscribe(data => console.log(`Observer 1: ${data}`));
obs.subscribe(data => console.log(`Observer 2: ${data}`));
obs.notify("Event Fired"); // Output: Observer 1: Event Fired, Observer 2: Event Fired
Module Pattern
Overview
The Module pattern is used to create a simple way to encapsulate methods and attributes, providing a 'privacy' and state retention mechanism. It is particularly useful for singletons or objects with a single instance.
Learn More About Module PatternExample
const Calculator = (() => {
// private methods
const add = (a, b) => a + b;
const sub = (a, b) => a - b;
return {
// public methods
operate: (op, a, b) => {
if (op === 'add') {
return add(a, b);
}
if (op === 'sub') {
return sub(a, b);
}
}
};
})();
console.log(Calculator.operate('add', 5, 3)); // Output: 8
Strategy Pattern
Overview
The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
Learn More About Strategy PatternExample
class SortStrategy {
sort(arr) {}
}
class BubbleSort extends SortStrategy {
sort(arr) {
// Bubble sort algorithm
return arr.sort((a, b) => a - b);
}
}
class QuickSort extends SortStrategy {
sort(arr) {
// Quick sort algorithm
return arr.sort((a, b) => a - b); // Placeholder
}
}
class Sorter {
constructor(strategy) {
this.strategy = strategy;
}
sort(arr) {
return this.strategy.sort(arr);
}
}
const bubbleSortStrategy = new BubbleSort();
const sorter = new Sorter(bubbleSortStrategy);
console.log(sorter.sort([5, 3, 9, 1])); // Output: [1, 3, 5, 9]
Conclusion
Design patterns offer flexible and clean ways to compose complex solutions in JavaScript. Understanding when and how to use them can significantly improve code readability and maintainability. While this article provides a starting point, the world of design patterns is rich and varied. Continuous learning and practice are essential for mastering them.
Essential JavaScript Design Patterns For Beginners by Addy Osmani is a highly recommended read for anyone wishing to delve deeper into this subject.