DEV Community

Cover image for Design Patterns in JavaScript β€” Explained with Practical Examples
chandra penugonda
chandra penugonda

Posted on

Design Patterns in JavaScript β€” Explained with Practical Examples

πŸš€ Design Patterns in JavaScript β€” Explained with Practical Examples

Design patterns are reusable solutions to common software design problems.

Instead of memorizing definitions, understand this:

A design pattern solves a recurring engineering problem.

In this article, we’ll walk through Creational, Structural, and Behavioral patterns with simple JavaScript examples.


πŸ— CREATIONAL PATTERNS

(How objects are created)


1️⃣ Factory Pattern

🧠 Core Idea

Hide object creation logic and delegate it to subclasses.

❓ Problem

You don’t want object creation logic scattered everywhere.

βœ… Example

class UPI {
  constructor() {
    console.log('upi class');
  }
}

class Card {
  constructor() {
    console.log('card class');
  }
}

class PaymentFactory {
  createPayment(type) {
    if (type === 'UPI') {
      return new UPI();
    } else if (type === 'Card') {
      return new Card();
    }
  }
}

const paymentFactory = new PaymentFactory();
paymentFactory.createPayment('UPI');
Enter fullscreen mode Exit fullscreen mode

🎯 When to Use

  • When object creation is complex
  • When multiple subclasses exist
  • When you want to hide instantiation logic

2️⃣ Builder Pattern

🧠 Core Idea

Construct complex objects step by step.

❓ Problem

Too many constructor parameters make code unreadable.

βœ… Example

class Car {
  constructor() {
    this.car = {};
  }

  setCar(car) {
    this.car = car;
    return this;
  }

  getCar() {
    return this.car;
  }
}

class CarBuilder {
  constructor() {
    this.car = new Car();
  }

  build() {
    return this.car;
  }
}

const carBuilder = new CarBuilder();
const car = carBuilder
  .build()
  .setCar({
    name: 'Car',
    color: 'Red',
    price: 1000000
  })
  .getCar();
Enter fullscreen mode Exit fullscreen mode

🎯 When to Use

  • When object creation involves many optional fields
  • When readability matters

3️⃣ Singleton Pattern

🧠 Core Idea

Only one instance of a class should exist.

❓ Problem

You don’t want multiple DB connections or config objects.

βœ… Example

class DBConnection {
  static instance;

  constructor() {
    if (DBConnection.instance) return DBConnection.instance;
    DBConnection.instance = this;
  }
}
Enter fullscreen mode Exit fullscreen mode

🎯 When to Use

  • Logger
  • Database connection
  • Configuration manager

4️⃣ Prototype Pattern

🧠 Core Idea

Clone an existing object instead of creating a new one.

❓ Problem

Object creation is expensive.

βœ… Example

const existingObject = {
  name: 'Car',
  color: 'Red',
  price: 1000000
};

const newObject = Object.create(existingObject);
console.log(newObject.color);
Enter fullscreen mode Exit fullscreen mode

🎯 When to Use

  • When object creation is costly
  • When cloning is cheaper than instantiation

🧱 STRUCTURAL PATTERNS

(How objects are composed)


5️⃣ Facade Pattern

🧠 Core Idea

Hide complex logic behind a simple interface.

❓ Problem

Clients shouldn’t know internal system complexity.

βœ… Example

class AuthService {
  check() {}
}

class OrderService {
  process() {}
}

class PaymentProcessor {
  constructor() {
    this.payment = new PaymentFactory();
    this.order = new OrderService();
    this.auth = new AuthService();
  }

  placeOrder() {
    this.auth.check();
    this.order.process();
    this.payment.createPayment('UPI');
  }
}

const paymentProcessor = new PaymentProcessor();
paymentProcessor.placeOrder();
Enter fullscreen mode Exit fullscreen mode

🎯 When to Use

  • To simplify large subsystems
  • To reduce coupling

6️⃣ Adapter Pattern

🧠 Core Idea

Convert one interface into another expected by the client.

❓ Problem

Legacy code doesn’t match your new interface.

βœ… Example

class OldApi {
  getUser() {
    console.log('adaptor pattern');
  }
}

class NewApi {
  constructor() {
    this.oldApi = new OldApi();
  }

  getUser() {
    return this.oldApi.getUser();
  }
}

const newApi = new NewApi();
newApi.getUser();
Enter fullscreen mode Exit fullscreen mode

🎯 When to Use

  • Integrating third-party libraries
  • Migrating legacy systems

7️⃣ Decorator Pattern

🧠 Core Idea

Add functionality without modifying original code.

❓ Problem

You want to extend behavior dynamically.

βœ… Example

function logger(fn) {
  return (...args) => {
    console.log('Running...');
    return fn.apply(this, args);
  };
}

function sum(a, b) {
  console.log(a + b);
}

const loggerSum = logger(sum);
loggerSum(1, 2);
Enter fullscreen mode Exit fullscreen mode

🎯 When to Use

  • Logging
  • Caching
  • Authentication wrappers

🧠 BEHAVIORAL PATTERNS

(How objects communicate and behave)


8️⃣ Strategy Pattern

🧠 Core Idea

Encapsulate algorithms and make them interchangeable.

❓ Problem

Too many if-else conditions for similar behaviors.

βœ… Example

class Strategy {
  execute() {
    throw new Error('Must implement execute');
  }
}

class ConcreteStrategyA extends Strategy {
  execute() {
    console.log('Executing strategy A');
  }
}

class ConcreteStrategyB extends Strategy {
  execute() {
    console.log('Executing strategy B');
  }
}

class Context {
  constructor(strategy) {
    this.strategy = strategy;
  }

  setStrategy(strategy) {
    this.strategy = strategy;
  }

  executeStrategy() {
    this.strategy.execute();
  }
}

const context = new Context(new ConcreteStrategyA());
context.executeStrategy();
context.setStrategy(new ConcreteStrategyB());
context.executeStrategy();
Enter fullscreen mode Exit fullscreen mode

9️⃣ Observer Pattern

🧠 Core Idea

Notify multiple objects when state changes.

❓ Problem

Many components depend on one object’s state.

βœ… Example

class Subject {
  constructor() {
    this.observers = [];
  }

  addObserver(observer) {
    this.observers.push(observer);
  }

  notifyObservers() {
    this.observers.forEach(observer => observer.update());
  }
}

class ConcreteObserver {
  update() {
    console.log('Observer updated');
  }
}

const subject = new Subject();
const observer = new ConcreteObserver();
subject.addObserver(observer);
subject.notifyObservers();
Enter fullscreen mode Exit fullscreen mode

πŸ”Ÿ State Pattern

🧠 Core Idea

Behavior changes when internal state changes.

❓ Problem

Too many conditional state checks.

βœ… Example

class State {
  execute() {
    throw new Error('Must implement execute');
  }
}

class ConcreteStateA extends State {
  execute() {
    console.log('Executing state A');
  }
}

class ConcreteStateB extends State {
  execute() {
    console.log('Executing state B');
  }
}

class Context {
  constructor(state) {
    this.state = state;
  }

  setState(state) {
    this.state = state;
  }

  executeState() {
    this.state.execute();
  }
}

const context = new Context(new ConcreteStateA());
context.executeState();
context.setState(new ConcreteStateB());
context.executeState();
Enter fullscreen mode Exit fullscreen mode

1️⃣1️⃣ Command Pattern

🧠 Core Idea

Encapsulate a request as an object.

❓ Problem

You want to queue, log, or undo actions.

βœ… Example

class Command {
  execute() {
    throw new Error('Must implement execute');
  }
}

class ConcreteCommandA extends Command {
  execute() {
    console.log('Executing command A');
  }
}

class ConcreteCommandB extends Command {
  execute() {
    console.log('Executing command B');
  }
}

class Context {
  constructor(command) {
    this.command = command;
  }

  setCommand(command) {
    this.command = command;
  }

  executeCommand() {
    this.command.execute();
  }
}

const context = new Context(new ConcreteCommandA());
context.executeCommand();
context.setCommand(new ConcreteCommandB());
context.executeCommand();
Enter fullscreen mode Exit fullscreen mode

🎯 Final Takeaway

Instead of memorizing names, remember problems:

Problem Pattern
Hide object creation Factory
Build complex object Builder
Only one instance Singleton
Clone object Prototype
Simplify complex system Facade
Convert interface Adapter
Extend functionality Decorator
Replace if-else logic Strategy
Notify subscribers Observer
Behavior changes by state State
Encapsulate request Command

Top comments (0)