디자인 패턴은 반복되는 설계 문제에 대한 검증된 해결책입니다. 자바스크립트에서 가장 실용적인 네 가지 패턴을 면접에서 설명할 수 있도록 정리했습니다.

Observer 패턴 — 이벤트 기반 설계

하나의 객체 상태가 변경되면 연관된 모든 객체에 자동 통지하는 패턴입니다. DOM 이벤트 시스템, React의 상태 관리가 이 패턴입니다.

JS
class EventEmitter {
  constructor() {
    this.listeners = new Map();
  }

  on(event, callback) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event).push(callback);
    return () => this.off(event, callback); // 구독 해제 함수 반환
  }

  off(event, callback) {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      this.listeners.set(event, callbacks.filter((cb) => cb !== callback));
    }
  }

  emit(event, data) {
    const callbacks = this.listeners.get(event) || [];
    callbacks.forEach((cb) => cb(data));
  }
}

// 사용
const store = new EventEmitter();
const unsubscribe = store.on("userLogin", (user) => {
  console.log(`${user.name}님이 로그인했습니다.`);
});

store.emit("userLogin", { name: "정훈" });
unsubscribe(); // 구독 해제

Strategy 패턴 — 알고리즘 교체

같은 인터페이스로 알고리즘을 교체할 수 있는 패턴입니다.

JS
// 결제 전략
const paymentStrategies = {
  creditCard: (amount) => {
    console.log(`신용카드로 ${amount}원 결제`);
    return { success: true, method: "creditCard" };
  },
  bankTransfer: (amount) => {
    console.log(`계좌이체로 ${amount}원 결제`);
    return { success: true, method: "bankTransfer" };
  },
  kakaoPay: (amount) => {
    console.log(`카카오페이로 ${amount}원 결제`);
    return { success: true, method: "kakaoPay" };
  },
};

function processPayment(amount, strategy) {
  const pay = paymentStrategies[strategy];
  if (!pay) throw new Error(`지원하지 않는 결제 방식: ${strategy}`);
  return pay(amount);
}

processPayment(10000, "kakaoPay");

// 정렬 전략
const sortStrategies = {
  price: (a, b) => a.price - b.price,
  name: (a, b) => a.name.localeCompare(b.name),
  date: (a, b) => new Date(b.date) - new Date(a.date),
  rating: (a, b) => b.rating - a.rating,
};

function sortProducts(products, strategy) {
  return [...products].sort(sortStrategies[strategy]);
}

Factory 패턴 — 객체 생성 위임

객체 생성 로직을 별도로 분리하여 유연성을 높이는 패턴입니다.

JS
// 알림 팩토리
class Notification {
  constructor(message) {
    this.message = message;
  }
  send() {
    throw new Error("send()를 구현해야 합니다.");
  }
}

class EmailNotification extends Notification {
  send() { console.log(`이메일 발송: ${this.message}`); }
}

class SMSNotification extends Notification {
  send() { console.log(`SMS 발송: ${this.message}`); }
}

class PushNotification extends Notification {
  send() { console.log(`푸시 알림: ${this.message}`); }
}

// 팩토리 함수
function createNotification(type, message) {
  const types = {
    email: EmailNotification,
    sms: SMSNotification,
    push: PushNotification,
  };

  const NotificationClass = types[type];
  if (!NotificationClass) throw new Error(`알 수 없는 타입: ${type}`);
  return new NotificationClass(message);
}

const notification = createNotification("email", "회의 알림");
notification.send();

// 함수형 팩토리 (자바스크립트에서 더 자연스러운 방식)
function createLogger(prefix) {
  return {
    log: (msg) => console.log(`[${prefix}] ${msg}`),
    warn: (msg) => console.warn(`[${prefix}] ${msg}`),
    error: (msg) => console.error(`[${prefix}] ${msg}`),
  };
}

const apiLogger = createLogger("API");
apiLogger.log("요청 시작");

Singleton 패턴 — 단일 인스턴스 보장

애플리케이션 전체에서 하나의 인스턴스만 사용하는 패턴입니다.

JS
// 클래스 기반 싱글톤
class Database {
  static instance = null;

  static getInstance() {
    if (!Database.instance) {
      Database.instance = new Database();
    }
    return Database.instance;
  }

  constructor() {
    if (Database.instance) {
      throw new Error("getInstance()를 사용하세요.");
    }
    this.connection = null;
  }

  connect(url) {
    this.connection = url;
    console.log(`DB 연결: ${url}`);
  }
}

const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true

// ES Module 싱글톤 (가장 자바스크립트다운 방식)
// config.js
const config = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
};
export default Object.freeze(config);
// ESM은 모듈 캐싱으로 자연스럽게 싱글톤

패턴 선택 가이드

패턴사용 시점JS 예시
Observer이벤트, 상태 변경 알림EventEmitter, DOM 이벤트
Strategy알고리즘 교체정렬, 결제, 검증 전략
Factory조건에 따른 객체 생성컴포넌트 생성, 로거
Singleton전역 단일 인스턴스DB 연결, 설정, 캐시

**기억하기 **: 자바스크립트에서는 클래스 기반보다 함수와 모듈을 활용한 패턴이 더 자연스럽습니다. Observer는 이벤트 시스템, Strategy는 객체/Map으로 전략 교체, Factory는 팩토리 함수, Singleton은 ES Module 캐싱으로 구현하는 것이 관용적입니다.

댓글 로딩 중...