PHpullh

JAVASCRIPT · 심층 가이드

JavaScript 패턴 완전 정리

전략, 옵저버, 빌더 같은 고전 디자인 패턴을 클래스 대신 클로저와 고차 함수로 다시 쓴 20편으로 JavaScript다운 설계 감각을 잡습니다.

주제 20개 · 예제 코드 포함 · 최종 수정 2026-08-30 · 작성 pullh 편집팀

고전 디자인 패턴 목록은 대부분 Java 시절의 제약 위에서 만들어졌습니다. 함수가 일급 값이고 객체 형태를 실행 중에 바꿀 수 있는 JavaScript에서는 같은 문제가 훨씬 작은 코드로 풀립니다. 전략 패턴은 함수를 인자로 넘기면 끝이고, 데코레이터는 함수를 감싸는 함수 하나면 됩니다. 그래서 여기서는 UML 구조를 옮기기보다 패턴이 해결하려던 문제가 무엇이었는지에 초점을 둡니다.

설정 객체부터 보면 나머지가 읽힙니다. 옵션을 객체 하나로 받는 습관이 빌더 패턴팩터리 메서드의 출발점이기 때문입니다. 전략 패턴·데코레이터·미들웨어 체인은 사실상 같은 계열로, 함수를 바꿔 끼우느냐 감싸느냐 줄줄이 엮느냐의 차이입니다. 데이터 접근 쪽은 저장소 패턴데이터 매퍼를 짝으로 읽어야 경계가 보이고, 캐시 래퍼retry 유틸은 그 위에 얹는 층입니다.

옵저버에서 가장 많이 새는 곳은 구독 해제입니다. 등록한 리스너를 떼어 내지 않으면 대상 객체가 콜백을, 콜백이 클로저를, 클로저가 다시 큰 객체를 붙잡아 메모리가 눌러앉습니다. 구독 함수가 해제 함수를 돌려주도록 만드는 것이 가장 안전한 계약입니다. 의존성 주입 컨테이너도 마찬가지로 순환 참조를 만들기 쉬우니, 등록 시점이 아니라 해석 시점에 순환을 감지하도록 짜 두는 편이 낫습니다.

01설정 객체

JavaScript에서 설정 객체 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 설정 객체
const strategies = { percent: (value) => value * 0.9, flat: (value) => value - 5 };
console.log(strategies.percent(100));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

02전략 패턴

JavaScript에서 전략 패턴 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 전략 패턴
const listeners = [];
const subscribe = (fn) => listeners.push(fn);
const publish = (value) => listeners.forEach(fn => fn(value));
subscribe(console.log);
publish("update-2");
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

03옵저버

JavaScript에서 옵저버 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 옵저버
const cache = new Map();
const getUser = (id) => { if (!cache.has(id)) cache.set(id, { id, name: "user" }); return cache.get(id); };
console.log(getUser(3));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

04데코레이터

JavaScript에서 데코레이터 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 데코레이터
const middlewares = [(ctx, next) => { ctx.steps.push("a"); return next(); }, (ctx, next) => { ctx.steps.push("b"); return next(); }];
const ctx = { steps: [] };
let index = -1;
const run = (i) => { if (i <= index) throw new Error("twice"); index = i; const mw = middlewares[i]; if (mw) return mw(ctx, () => run(i + 1)); };
run(0);
console.log(ctx.steps);
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

05어댑터

JavaScript에서 어댑터 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 어댑터
const strategies = { percent: (value) => value * 0.9, flat: (value) => value - 5 };
console.log(strategies.percent(100));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

06커맨드

JavaScript에서 커맨드 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 커맨드
const listeners = [];
const subscribe = (fn) => listeners.push(fn);
const publish = (value) => listeners.forEach(fn => fn(value));
subscribe(console.log);
publish("update-6");
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

07상태 패턴

JavaScript에서 상태 패턴 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 상태 패턴
const cache = new Map();
const getUser = (id) => { if (!cache.has(id)) cache.set(id, { id, name: "user" }); return cache.get(id); };
console.log(getUser(7));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

08팩터리 메서드

JavaScript에서 팩터리 메서드 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 팩터리 메서드
const middlewares = [(ctx, next) => { ctx.steps.push("a"); return next(); }, (ctx, next) => { ctx.steps.push("b"); return next(); }];
const ctx = { steps: [] };
let index = -1;
const run = (i) => { if (i <= index) throw new Error("twice"); index = i; const mw = middlewares[i]; if (mw) return mw(ctx, () => run(i + 1)); };
run(0);
console.log(ctx.steps);
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

09빌더 패턴

JavaScript에서 빌더 패턴 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 빌더 패턴
const strategies = { percent: (value) => value * 0.9, flat: (value) => value - 5 };
console.log(strategies.percent(100));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

10캐시 래퍼

JavaScript에서 캐시 래퍼 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 캐시 래퍼
const listeners = [];
const subscribe = (fn) => listeners.push(fn);
const publish = (value) => listeners.forEach(fn => fn(value));
subscribe(console.log);
publish("update-10");
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

11retry 유틸

JavaScript에서 retry 유틸 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// retry 유틸
const cache = new Map();
const getUser = (id) => { if (!cache.has(id)) cache.set(id, { id, name: "user" }); return cache.get(id); };
console.log(getUser(11));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

12미들웨어 체인

JavaScript에서 미들웨어 체인 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 미들웨어 체인
const middlewares = [(ctx, next) => { ctx.steps.push("a"); return next(); }, (ctx, next) => { ctx.steps.push("b"); return next(); }];
const ctx = { steps: [] };
let index = -1;
const run = (i) => { if (i <= index) throw new Error("twice"); index = i; const mw = middlewares[i]; if (mw) return mw(ctx, () => run(i + 1)); };
run(0);
console.log(ctx.steps);
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

13검증기 조합

JavaScript에서 검증기 조합 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 검증기 조합
const strategies = { percent: (value) => value * 0.9, flat: (value) => value - 5 };
console.log(strategies.percent(100));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

14포매터 파이프

JavaScript에서 포매터 파이프 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 포매터 파이프
const listeners = [];
const subscribe = (fn) => listeners.push(fn);
const publish = (value) => listeners.forEach(fn => fn(value));
subscribe(console.log);
publish("update-14");
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

15페이지네이션

JavaScript에서 페이지네이션 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 페이지네이션
const cache = new Map();
const getUser = (id) => { if (!cache.has(id)) cache.set(id, { id, name: "user" }); return cache.get(id); };
console.log(getUser(15));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

16데이터 매퍼

JavaScript에서 데이터 매퍼 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 데이터 매퍼
const middlewares = [(ctx, next) => { ctx.steps.push("a"); return next(); }, (ctx, next) => { ctx.steps.push("b"); return next(); }];
const ctx = { steps: [] };
let index = -1;
const run = (i) => { if (i <= index) throw new Error("twice"); index = i; const mw = middlewares[i]; if (mw) return mw(ctx, () => run(i + 1)); };
run(0);
console.log(ctx.steps);
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

17저장소 패턴

JavaScript에서 저장소 패턴 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 저장소 패턴
const strategies = { percent: (value) => value * 0.9, flat: (value) => value - 5 };
console.log(strategies.percent(100));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

18의존성 주입 컨테이너

JavaScript에서 의존성 주입 컨테이너 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 의존성 주입 컨테이너
const listeners = [];
const subscribe = (fn) => listeners.push(fn);
const publish = (value) => listeners.forEach(fn => fn(value));
subscribe(console.log);
publish("update-18");
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

19템플릿 메서드

JavaScript에서 템플릿 메서드 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 템플릿 메서드
const cache = new Map();
const getUser = (id) => { if (!cache.has(id)) cache.set(id, { id, name: "user" }); return cache.get(id); };
console.log(getUser(19));
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

20파사드

JavaScript에서 파사드 개념을 코드로 빠르게 확인하는 패턴 예제입니다.

JavaScript code

// 파사드
const middlewares = [(ctx, next) => { ctx.steps.push("a"); return next(); }, (ctx, next) => { ctx.steps.push("b"); return next(); }];
const ctx = { steps: [] };
let index = -1;
const run = (i) => { if (i <= index) throw new Error("twice"); index = i; const mw = middlewares[i]; if (mw) return mw(ctx, () => run(i + 1)); };
run(0);
console.log(ctx.steps);
알아두면 좋은 점

패턴은 이름보다 책임 분리와 교체 가능성에 주목하면 더 실용적으로 이해됩니다.

자주 하는 실수

패턴 이름만 따라 하고 결합도를 줄이지 못하면 구조가 오히려 더 복잡해집니다.

정리하며

  • 전략과 데코레이터는 클래스 계층 없이 함수 인자와 래핑만으로 충분합니다
  • 구독 함수는 항상 해제 함수를 반환하도록 만들어 리스너 누수를 막습니다
  • 옵션이 세 개를 넘어가면 위치 인자 대신 설정 객체 하나로 받습니다
  • 저장소 패턴으로 도메인 로직과 데이터 접근 코드의 경계를 고정합니다

더 깊이 들어가고 싶다면 JavaScript 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.