Design Patterns
📖 Concept
Design patterns are proven solutions to common programming problems. They provide templates for writing maintainable, scalable, and reusable code.
Creational: Singleton, Factory Structural: Module, Proxy, Decorator Behavioral: Observer, Strategy, Pub/Sub, Command
🏠 Real-world analogy: Design patterns are like architectural blueprints. The "Observer" pattern is like a newspaper subscription — when news (data) changes, all subscribers (components) are automatically notified. No need to check manually.
💻 Code Example
1// Module Pattern (encapsulation)2const UserModule = (() => {3 let users = []; // Private4 return {5 add(user) { users.push(user); },6 getAll() { return [...users]; },7 findById(id) { return users.find(u => u.id === id); }8 };9})();1011// Singleton Pattern12class Database {13 constructor() {14 if (Database.instance) return Database.instance;15 this.connection = "connected";16 Database.instance = this;17 }18 static getInstance() {19 if (!Database.instance) new Database();20 return Database.instance;21 }22}2324// Observer Pattern (Event Emitter)25class EventEmitter {26 constructor() { this.events = {}; }27 on(event, listener) {28 (this.events[event] ||= []).push(listener);29 return () => this.off(event, listener); // Return unsubscribe30 }31 off(event, listener) {32 this.events[event] = this.events[event]?.filter(l => l !== listener);33 }34 emit(event, ...args) {35 this.events[event]?.forEach(listener => listener(...args));36 }37}3839// Factory Pattern40class Shape {41 static create(type, ...args) {42 switch (type) {43 case "circle": return new Circle(...args);44 case "square": return new Square(...args);45 case "triangle": return new Triangle(...args);46 default: throw new Error(`Unknown shape: ${type}`);47 }48 }49}5051// Strategy Pattern52class Sorter {53 constructor(strategy) { this.strategy = strategy; }54 sort(data) { return this.strategy(data); }55 setStrategy(strategy) { this.strategy = strategy; }56}57const bubbleSort = (data) => { /* ... */ return data; };58const quickSort = (data) => { /* ... */ return data; };59const sorter = new Sorter(quickSort);6061// Pub/Sub Pattern62class PubSub {63 constructor() { this.topics = {}; }64 subscribe(topic, handler) {65 (this.topics[topic] ||= []).push(handler);66 return { unsubscribe: () => {67 this.topics[topic] = this.topics[topic].filter(h => h !== handler);68 }};69 }70 publish(topic, data) {71 this.topics[topic]?.forEach(handler => handler(data));72 }73}
🏋️ Practice Exercise
Mini Exercise:
- Implement a Pub/Sub system for a todo app (add, complete, delete events)
- Create a Factory that produces different notification types (email, SMS, push)
- Implement the Strategy pattern for different payment methods
- Build an Observer pattern for a reactive state management system
⚠️ Common Mistakes
Overusing Singletons — they create hidden global state and make testing harder
Observer pattern without cleanup — forgetting to unsubscribe causes memory leaks
Factory pattern overkill — don't use a factory when a simple constructor suffices
Forcing patterns where they don't fit — patterns solve specific problems; don't use them just because
Not considering JavaScript-specific patterns — many OOP patterns from Java/C++ have simpler JS alternatives
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for Design Patterns. Login to unlock this feature.