Design Patterns
Singleton Pattern
class Singleton {
constructor() {
if (Singleton.instance) return Singleton.instance;
this.data = {
name: "Pawan",
age: 25,
};
Singleton.instance = this;
}
getData = () => this.data;
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); //true
console.log(instance1.getData()); //{ name: 'Pawan', age: 25 }
console.log(instance1.getData()); //{ name: 'Pawan', age: 25 }
Factory Pattern
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayGreeting = () => {
console.log(`Hello , this is ${this.name} and I am ${this.age} years old`);
};
}
class PersonFactory {
static createPerson(name, age) {
return new Person(name, age);
}
}
const p1 = PersonFactory.createPerson("Pawan", 25);
const p2 = PersonFactory.createPerson("Ayush", 26);
p1.sayGreeting(); //Hello , this is Pawan and I am 25 years old
p2.sayGreeting(); //Hello , this is Ayush and I am 26 years old
Module Pattern
class MyModule {
#privateChar = "I'm private";
#getPrivateChar = () => {
console.log("I'm private method");
};
publicMethod = () => {
console.log("I'm public method");
};
}
const mm = new MyModule();
mm.publicMethod(); //I'm public method
// mm.#getPrivateChar(); //Property '#getPrivateChar' is not accessible outside class 'MyModule' because it has a private identifier.
// mm.#privateChar; //Property '#privateChar' is not accessible outside class 'MyModule' because it has a private identifier.
Proxy Pattern
const person = {
name: "pawan",
age: 25,
};
const handler = {
get: (target, key) => {
if (key === "name") return target[key].toUpperCase();
},
set: (target, key, value) => {
if (key === "address") {
key = key + "01";
}
target[key] = value;
},
};
const proxy = new Proxy(person, handler);
proxy["address"] = "Lucknow";
console.log(proxy); //{ name: 'pawan', age: 25, address01: 'Lucknow' }
Builder Pattern
class Product {
constructor(name, price, category) {
this.name = name;
this.price = price;
this.category = category;
}
}
class ProductBuilder {
constructor(name) {
this.product = new Product();
this.product.name = name;
}
withPrice = (price) => {
this.product.price = price;
return this;
};
isCategory = (category) => {
this.product.category = category;
return this;
};
build = () => {
return this;
};
}
const product = new ProductBuilder("Widget")
.withPrice(19.99)
.isCategory("Gadgets")
.build();
console.log(product.product);
CircuitBreaker Pattern
class CircuitBreaker {
constructor(threshold, timeout) {
this.threshold = threshold; // number of failures before tripping the circuit
this.timeout = timeout; // time to wait before attempting to call the service again
this.failureCount = 0; // number of consecutive failures
this.lastFailureTime = null; // time of the last failure
this.isCircuitOpen = false; // whether the circuit is currently open
}
async callService() {
if (this.isCircuitOpen) {
const now = Date.now();
if (now - this.lastFailureTime > this.timeout) {
this.isCircuitOpen = false;
this.failureCount = 0;
} else {
throw new Error("Circuit is open");
}
}
try {
// Call the service here
const result = await someServiceCall();
this.failureCount = 0;
return result;
} catch (error) {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.threshold) {
this.isCircuitOpen = true;
}
throw error;
}
}
}
EvenStreamer Pattern
class EventSteamer {
constructor() {
this.listeners = {};
}
on = (event, listener) => {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(listener);
};
off = (event, listener) => {
if (this.listeners[event]) {
this.listeners[event] = this.listeners[event].filter(
(fn) => fn !== listener
);
}
};
emit = (event, data) => {
if (this.listeners[event]) {
this.listeners[event].forEach((listener) => listener(data));
}
};
}
const es = new EventSteamer();
function handleData(data) {
console.log("Receiver data", data);
}
es.on("data", handleData);
es.emit("data", "Sample Data"); //Receiver data Sample Data
es.off("data", handleData);
es.emit("data", "Another Data"); //No data as the handler has been removed
Iterator Pattern
const iterator = (collection) => {
let idx = 0;
return {
next: () =>
idx < collection.length
? { value: collection[idx++], done: false }
: { done: true },
};
};
const arr = [1, 2, 3, 4];
const iter = iterator(arr);
console.log(iter.next()); //{ value: 1, done: false }
console.log(iter.next()); //{ value: 2, done: false }
console.log(iter.next()); //{ value: 3, done: false }
console.log(iter.next()); //{ value: 4, done: false }
console.log(iter.next()); //{ done: true }
Observer Pattern
class Observer {
update = (message) => {
console.log("Received Message", message);
};
}
class Subject {
constructor() {
this.observers = [];
}
addObserver = (observer) => {
this.observers.push(observer);
};
removerObserver = (observer) => {
this.observers = this.observers.filter((obs) => obs !== observer);
};
notifyObservers = (message) => {
this.observers.forEach((obs) => obs.update(message));
};
}
const subject = new Subject();
const ob1 = new Observer();
const ob2 = new Observer();
subject.addObserver(ob1);
subject.addObserver(ob2);
subject.notifyObservers("Hello Observers");
subject.removerObserver(ob1);
subject.notifyObservers("Observers, are you still there?");
PubSub Pattern
class PubSub {
constructor() {
this.subscribers = {};
}
subscribe = (event, cb) => {
if (!this.subscribers[event]) {
this.subscribers[event] = [];
}
this.subscribers[event].push(cb);
};
publish = (event, data) => {
if (this.subscribers[event]) {
this.subscribers[event].forEach((cb) => cb(data));
}
};
unSubscribe = (event, callback) => {
if (this.subscribers[event]) {
this.subscribers[event] = this.subscribers[event].filter(
(cb) => cb !== callback
);
}
};
}
const ps = new PubSub();
function subscriber1(data) {
console.log("Subscriber1 recieved data", data);
}
function subscriber2(data) {
console.log("Subscriber2 recieved data", data);
}
ps.subscribe("myEvent", subscriber1); //Subscriber1 recieved data Hello Love...
ps.subscribe("myEvent", subscriber2); //Subscriber2 recieved data Hello Love...
ps.publish("myEvent", "Hello Love...");
ps.unSubscribe("myEvent", subscriber1);
ps.publish("myEvent", "unsubscribed from s1"); //Subscriber2 recieved data unsubscribed from s1