Design Patterns
Design patterns = proven solutions to common problems
What are Design Patterns?
"Reusable solutions to recurring problems"
Design patterns are:
- Proven solutions to common problems
- Reusable templates
- Language-agnostic concepts
- Best practices in software design
"Design patterns are reusable solutions to common software design problems that provide proven approaches to structuring code."
Categories of Patterns
Creational · Structural · Behavioral
| Category | Purpose | Examples |
|---|---|---|
| Creational | Object creation | Singleton, Factory |
| Structural | Object composition | Adapter, Decorator |
| Behavioral | Object interaction | Observer, Strategy |
Singleton Pattern
One instance only
class Singleton {
static instance;
static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
Use when: Need single instance (config, logger)
"Singleton ensures only one instance of a class exists, useful for shared resources."
Factory Pattern
Create objects without specifying exact class
class ButtonFactory {
createButton(type) {
if (type === "primary") return new PrimaryButton();
if (type === "secondary") return new SecondaryButton();
}
}
Use when: Object creation logic is complex
"Factory pattern encapsulates object creation, providing a way to create objects without specifying their exact classes."
Observer Pattern
Subscribe and notify
class Subject {
observers = [];
subscribe(observer) {
this.observers.push(observer);
}
notify(data) {
this.observers.forEach((o) => o.update(data));
}
}
Use when: Need to notify multiple objects of changes
"Observer pattern defines a one-to-many dependency where observers are notified of state changes."
Module Pattern
Encapsulate private/public
const Module = (function () {
let private = "hidden";
return {
public: "visible",
getPrivate: () => private,
};
})();
Use when: Need to encapsulate code and create namespaces
"Module pattern uses closures to create private and public members, providing encapsulation."
Strategy Pattern
Interchangeable algorithms
class PaymentProcessor {
constructor(strategy) {
this.strategy = strategy;
}
process(amount) {
return this.strategy.pay(amount);
}
}
Use when: Multiple ways to perform a task
"Strategy pattern defines a family of algorithms and makes them interchangeable."
Adapter Pattern
Bridge incompatible interfaces
class OldAPI {
oldMethod() {
return "data";
}
}
class Adapter {
constructor(oldAPI) {
this.api = oldAPI;
}
newMethod() {
return this.api.oldMethod();
}
}
Use when: Need to use incompatible interfaces together
"Adapter pattern allows incompatible interfaces to work together by wrapping one interface with another."
9️⃣ Decorator Pattern
Add behavior dynamically
class Coffee {
cost() {
return 5;
}
}
class MilkDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2;
}
}
Use when: Need to add responsibilities to objects dynamically
"Decorator pattern adds behavior to objects dynamically without altering their structure."
React-Specific Patterns
HOC · Render Props · Hooks
- HOC (Higher-Order Component): Component wrapper
- Render Props: Function as prop
- Custom Hooks: Reusable logic
- Compound Components: Related components together
"React uses patterns like HOCs, render props, and custom hooks for code reuse and composition."
"Design patterns are reusable solutions to common problems. Creational patterns handle object creation (Singleton, Factory), structural patterns organize objects (Adapter, Decorator), and behavioral patterns manage object communication (Observer, Strategy). In front-end development, patterns like Module, Observer, and React-specific patterns (HOCs, hooks) are commonly used."
🧠 Ultra-Short Cheat Sheet
Creational (Singleton, Factory)
Structural (Adapter, Decorator)
Behavioral (Observer, Strategy)
Module pattern
React patterns (HOC, Hooks)
Reusable solutions