컴퓨터 과학 (자바 디자인 패턴)

자바 디자인 패턴 개념 정리

GoF 23개 패턴 + 동시성 패턴 + 안티패턴 + SOLID 원칙을, 의도·구조·Java 표준 라이브러리 적용 사례·모던 Java(21+) 변형 중심으로 정리. 실무에서 자주 마주치고 서로 헷갈리기 쉬운 항목을 우선했다.

읽는 법 — 각 카테고리는 ① 요약 표(한눈에) → ② 패턴별 핵심 노트(의도·JDK·주의) 순서. 헷갈리는 패턴 비교는 §7에 모았다.


📌 0. 기초 용어 사전

0.1 패턴이란

  • 디자인 패턴(Design Pattern) — 자주 반복되는 설계 문제에 대한 검증된 해법 템플릿. 코드가 아니라 설계 아이디어다.
  • GoF (Gang of Four)Design Patterns (1994) 저자 4인(Gamma·Helm·Johnson·Vlissides). 23개 패턴을 생성·구조·행위 3분류로 정리.
  • 패턴의 4요소이름 · 문제(언제) · 해법(구조) · 결과(trade-off).

추상화 수준 구분 (작은 것 → 큰 것)

용어범위
이디엄(idiom)한 언어 한정 관용구Java try-with-resources, equals/hashCode
디자인 패턴언어 무관 객체 설계Strategy, Observer
아키텍처 패턴시스템 구조MVC, 레이어드, 헥사고날

0.2 OOP·결합 핵심 용어

  • 결합도(Coupling) — 모듈 간 의존 정도. 낮을수록 좋다(loose coupling).
  • 응집도(Cohesion) — 한 모듈이 한 가지 책임에 집중하는 정도. 높을수록 좋다.
  • 캡슐화·추상화·상속·다형성 — OOP 4대 특성. 패턴 대부분은 다형성 + 합성으로 변화를 흡수한다.
  • 위임(Delegation) — 일을 다른 객체에게 넘겨 처리. 상속의 대안으로 패턴의 핵심 메커니즘.

0.3 GoF의 2대 설계 원칙 ⭐

  1. 구현이 아니라 인터페이스에 프로그래밍하라 (Program to an interface, not an implementation)
    • 구체 클래스가 아닌 추상 타입(인터페이스) 에 의존 → 구현 교체가 자유로움.
  2. 상속보다 객체 합성을 선호하라 (Favor object composition over class inheritance)
    • 상속은 컴파일 타임 고정·캡슐화 약화. 합성은 런타임 교체 가능 → 유연.

이 두 원칙이 거의 모든 패턴의 뿌리다. Strategy·Decorator·Bridge·State가 대표적.

0.4 UML 관계 표기 (다이어그램 읽기)

관계화살표의미
일반화(상속)─▷ (빈 삼각형)is-a, extends
실체화(구현)┈▷ (점선+빈삼각형)implements
연관(association)참조 보유
집약(aggregation)◇→ (빈 마름모)has-a, 약한 소유(부품 독립 생존)
합성(composition)◆→ (찬 마름모)has-a, 강한 소유(전체 사라지면 부품도 소멸)
의존(dependency)┈>파라미터·지역변수로 잠깐 사용

📌 1. SOLID 원칙 — 패턴의 토대

암기: SOLID = S·O·L·I·D

원칙정의한 줄위반 신호관련 패턴
SRP 단일 책임클래스는 하나의 변경 이유"왜 바뀌나?"가 둘이면 분리한 클래스가 UI+DB+검증Facade, Mediator
OCP 개방-폐쇄확장엔 열고, 변경엔 닫고새 기능 = 코드 추가, 기존 수정 X새 타입마다 if/switch 증식Strategy, Template Method, Decorator
LSP 리스코프 치환자식은 부모를 완전히 대체 가능자식이 부모 계약을 깨면 위반Square extends Rectangle, 예외 던지는 오버라이드(상속 설계 전반)
ISP 인터페이스 분리안 쓰는 메서드에 의존 강요 X큰 인터페이스 → 작게 쪼개기빈 구현(throw new UnsupportedOperation)Adapter
DIP 의존 역전추상에 의존, 구체에 의존 X고수준이 저수준 구체를 직접 new상위 모듈이 new MySqlRepo()Factory, DI(IoC)
  • OCP의 실현 도구가 곧 다형성 — 분기문 대신 인터페이스 + 구현 교체.
  • DIP ≈ DI(의존성 주입)·IoC(제어의 역전) — Spring의 핵심.

📌 2. 생성 패턴 (Creational · 5개)

객체 생성을 캡슐화 — 무엇을·어떻게 만들지를 사용처에서 분리. 암기: 싱·팩·추·빌·프

패턴의도대표 JDK 예
Singleton인스턴스 딱 하나 + 전역 접근Runtime.getRuntime(), Desktop.getDesktop()
Factory Method어떤 객체를 만들지 하위 클래스가 결정Calendar.getInstance(), NumberFormat.getInstance()
Abstract Factory관련 객체 군(family) 을 일관되게 생성DocumentBuilderFactory.newInstance(), TransformerFactory
Builder복잡한 객체를 단계별로 조립StringBuilder, Stream.Builder, Locale.Builder
Prototype기존 객체를 복제해 생성Object.clone() + Cloneable

Singleton — 단 하나의 인스턴스

  • 핵심: private 생성자 + 정적 접근자. 설정·로거·커넥션풀 등 공유 자원.
  • 모던 Java(권장): enum 싱글톤 — 직렬화·리플렉션 공격에 안전 (Effective Java Item 3).
    public enum Config { INSTANCE; public String url() { return url; } }
    
  • 지연 초기화 + 스레드 안전: volatile + DCL(이중 검사 잠금), 또는 holder idiom(정적 중첩 클래스).
  • 주의: 전역 상태 → 테스트 곤란·결합도 ↑. 안티패턴화되기 쉬움 (§6 참고).

Factory Method — 생성 책임을 하위 클래스로

  • 핵심: 상위에 createXxx() 추상 메서드, 하위가 어떤 구체 클래스를 반환할지 결정.
  • 정적 팩토리 메서드와 구별 — of()·valueOf()·getInstance()는 GoF Factory Method가 아니라 Effective Java Item 1의 관용구지만 실무에서 같이 묶어 부른다.
  • JDK: Calendar.getInstance(), Iterator iterator(), java.sql.Connection.createStatement().

Abstract Factory — 제품 군을 통째로

  • 핵심: 서로 어울리는 객체 세트를 만드는 팩토리 인터페이스. (예: GTK 버튼+GTK 체크박스 vs Win 버튼+Win 체크박스)
  • Factory Method와 차이: Factory Method = 한 제품, Abstract Factory = 제품 군 여러 개 (§7 비교).
  • JDK: DocumentBuilderFactory, TransformerFactory, XPathFactory — 모두 newInstance().

Builder — 복잡한 생성자 길들이기

  • 핵심: 선택 인자가 많을 때 점층적 생성자(telescoping) 대신 메서드 체이닝으로 조립.
  • Effective Java Item 2 권장. 가독성·불변성 동시 확보.
    var http = HttpRequest.newBuilder().uri(uri).GET().timeout(D).build();
    
  • 모던: record + 정적 팩토리로 단순 케이스 대체 가능, Lombok @Builder.
  • JDK: StringBuilder/StringBuffer, Stream.Builder, Locale.Builder, HttpRequest.Builder.

Prototype — 복제로 생성

  • 핵심: new 비용이 크거나 런타임에 타입이 정해질 때 원본을 복사.
  • 모던(권장): Cloneable/clone()은 결함 많음 → 복사 생성자·복사 정적 팩토리 선호 (Effective Java Item 13).
  • JDK: Object.clone(), ArrayList·HashMapclone().

📌 3. 구조 패턴 (Structural · 7개)

객체를 조합해 더 큰 구조를 만들거나 인터페이스를 맞춘다. 암기: 어·브·컴·데·퍼·플·프

패턴한 줄 의도대표 JDK 예
Adapter호환 안 되는 인터페이스를 맞춰줌 (변환)Arrays.asList(), InputStreamReader
Bridge추상구현을 분리해 독립 확장JDBC Driver, AWT 컴포넌트↔Peer
Composite개별·복합 객체를 동일하게 다룸 (트리)java.awt.Container, Swing JComponent
Decorator객체를 감싸 기능을 동적 추가java.io 스트림, Collections.unmodifiableXxx
Facade복잡한 서브시스템에 단순 창구 제공javax.faces, Spring JdbcTemplate(외부)
Flyweight공유로 메모리 절약(불변 내부 상태)Integer.valueOf()(캐시), 문자열 풀
Proxy대상 객체 접근을 대리·제어java.lang.reflect.Proxy, RMI, Spring AOP

Adapter — 인터페이스 변환기

  • 핵심: 기존 클래스를 클라이언트가 기대하는 인터페이스로 감싸 변환. "콘센트 어댑터".
  • JDK: Arrays.asList(arr)(배열→List), InputStreamReader(바이트→문자), Collections.list(enumeration).

Bridge — 추상과 구현을 분리

  • 핵심: 두 축이 각자 변하면(예: 도형 × 렌더링 방식) 합성으로 연결해 곱집합 폭발을 막음.
  • Adapter와 차이: Adapter는 사후에 안 맞는 걸 맞춤, Bridge는 설계 단계부터 분리 (§7).
  • JDK: JDBC API(추상) ↔ 드라이버 구현, AWT ComponentComponentPeer.

Composite — 부분-전체 트리

  • 핵심: 잎(Leaf)과 가지(Composite)가 같은 인터페이스 → 재귀적으로 동일 처리.
  • JDK: java.awt.Container(Component를 담는 Component), Swing 컴포넌트 트리, org.w3c.dom.Node.

Decorator — 래핑으로 기능 추가 ⭐

  • 핵심: 대상과 같은 인터페이스를 구현하면서 감싸서 책임을 덧붙임. 상속 대신 런타임 조합.
  • 상속과 차이: 상속은 컴파일 타임 고정, Decorator는 여러 겹 동적 조합 (new BufferedInputStream(new FileInputStream(f))).
  • JDK: java.io(Buffered·Data·GZIP 스트림), Collections.synchronizedList/unmodifiableList/checkedList.

Facade — 단순화된 창구

  • 핵심: 복잡한 내부 호출들을 하나의 고수준 인터페이스로 감싼다. 서브시스템을 숨기지 않고 단순화.
  • Decorator와 차이: Facade는 인터페이스를 단순화, Decorator는 같은 인터페이스 유지 + 기능 추가.
  • : Spring JdbcTemplate, SLF4J 로깅 파사드(외부 라이브러리에서 흔함).

Flyweight — 공유로 메모리 절약

  • 핵심: 변하지 않는 내부 상태(intrinsic) 를 공유 객체로, 변하는 외부 상태(extrinsic) 는 인자로 전달.
  • JDK: Integer.valueOf()/Long.valueOf() (−128~127 캐시), Boolean.valueOf(), Character.valueOf(), 문자열 상수 풀(String.intern()).
    Integer.valueOf(100) == Integer.valueOf(100) // true (캐시 공유)
    Integer.valueOf(200) == Integer.valueOf(200) // false (범위 밖)
    

Proxy — 대리·접근 제어

  • 핵심: 대상과 같은 인터페이스를 가진 대리인이 접근을 통제. 종류: 가상(지연 로딩)·보호(권한)·원격(RMI)·로깅/캐싱.
  • Decorator와 차이: Decorator는 기능 추가, Proxy는 접근 제어 (둘 다 같은 인터페이스로 감쌈).
  • JDK: java.lang.reflect.Proxy(동적 프록시), RMI 스텁, Spring AOP(트랜잭션·@Transactional).

📌 4. 행위 패턴 (Behavioral · 11개)

객체 간 책임 분배와 통신. 11개로 가장 많다. 암기: 책·커·인·이·중·메·옵·상·전·템·비

패턴한 줄 의도대표 JDK 예
Chain of Responsibility처리자 사슬로 요청 위임Servlet FilterChain, Logger 부모 위임
Command요청을 객체로 캡슐화 (실행 분리·취소)Runnable, Callable, Swing Action
Interpreter문법 규칙을 클래스로 표현·해석java.util.regex.Pattern, java.text.Format
Iterator컬렉션 내부 노출 없이 순회Iterator, Enumeration, for-each
Mediator객체 간 통신을 중재자로 집중ExecutorService(작업↔스레드, 개념적)
Memento캡슐화 깨지 않고 상태 저장·복원직렬화(Serializable) 기반 스냅샷
Observer상태 변화를 구독자에 통지 (1:N)PropertyChangeListener, Flow.Subscriber
State상태에 따라 행동을 바꿈(개념 — enum+추상 메서드로 구현)
Strategy알고리즘을 교체 가능하게 캡슐화Comparator, RejectedExecutionHandler
Template Method알고리즘 골격은 고정, 일부만 하위 구현AbstractList, InputStream.read()
Visitor구조는 두고 연산을 외부 추가FileVisitor(Files.walkFileTree)

Chain of Responsibility — 처리 사슬

  • 핵심: 요청을 처리할 수 있을 때까지 다음 핸들러로 넘김. 송신자-수신자 결합 해제.
  • JDK: javax.servlet.Filter/FilterChain, java.util.logging.Logger(부모 로거로 위임), 예외 전파.

Command — 요청의 객체화

  • 핵심: 동작 + 인자를 객체로 포장 → 큐잉·로깅·undo/redo 가능.
  • 모던: 인터페이스가 단일 메서드면 람다로 대체 (Runnable r = () -> ...).
  • JDK: Runnable, Callable, java.util.concurrent 작업 제출.

Interpreter — 문법 해석

  • 핵심: 간단한 언어/문법을 클래스 트리로 표현하고 해석. (DSL·수식·정규식)
  • JDK: java.util.regex.Pattern, java.text.MessageFormat/DecimalFormat.

Iterator — 일관된 순회

  • 핵심: 컬렉션의 내부 표현을 숨긴 채 원소를 차례로 접근.
  • 모던: Iterable 구현 → for-each, Stream으로 선언형 순회.
  • JDK: java.util.Iterator, Enumeration(레거시).

Mediator — 중재자

  • 핵심: 다대다로 얽힌 객체들을 중재자 하나에 연결 → 결합도 ↓. (관제탑이 비행기끼리 직접 통신 막음)
  • Observer와 차이: Mediator = 양방향 조정, Observer = 단방향 통지 (§7).

Memento — 스냅샷·복원

  • 핵심: 객체 내부 상태를 캡슐화 유지한 채 저장했다가 되돌림. (Ctrl+Z)
  • 구성: Originator(원본)·Memento(스냅샷)·Caretaker(보관자).

Observer — 발행/구독 ⭐

  • 핵심: Subject 상태가 바뀌면 등록된 Observer들에 자동 통지 (1:N). 느슨한 결합.
  • 모던: java.util.Observer/ObservableJava 9부터 deprecatedPropertyChangeListener, Reactive Streams(Flow.Publisher/Subscriber), 외부 라이브러리(RxJava) 사용.
  • JDK: Swing 이벤트 리스너, java.beans.PropertyChangeListener.

State — 상태 기계

  • 핵심: 객체의 상태를 클래스로 만들어, 상태마다 다른 행동 + 전이를 캡슐화. if(state==…) 분기 제거.
  • Strategy와 차이: 구조는 같지만 State는 스스로 다음 상태로 전이, Strategy는 외부가 알고리즘 선택 (§7).
  • 모던: enum + 추상 메서드로 간결 구현.

Strategy — 알고리즘 교체 ⭐

  • 핵심: 알고리즘 군을 인터페이스로 캡슐화해 런타임 교체. OCP의 교과서적 실현.
  • 모던: 함수형 인터페이스 → 람다·메서드 참조로 전략 주입.
    list.sort(Comparator.comparing(User::age)); // 전략 = 람다
    
  • JDK: Comparator, ThreadPoolExecutorRejectedExecutionHandler, Collections.sort(list, cmp).

Template Method — 골격 고정 ⭐

  • 핵심: 상위가 알고리즘 뼈대를 정의하고, 변하는 단계만 하위가 오버라이드. 상속 기반.
  • Strategy와 차이: Template Method = 상속(컴파일 타임), Strategy = 합성(런타임) (§7).
  • JDK: AbstractList/AbstractMap(get,size만 구현), InputStream.read(), HttpServlet.service()doGet/doPost.

Visitor — 연산의 외부화

  • 핵심: 객체 구조는 그대로 두고, 새 연산을 Visitor로 추가 (double dispatch). 구조 안정 + 연산 자주 추가일 때.
  • 단점: 새 요소 타입 추가는 모든 Visitor 수정 필요.
  • 모던(대안): sealed 인터페이스 + switch 패턴 매칭(Java 21)이 닫힌 타입 계층에서 Visitor를 대체.
    sealed interface Shape permits Circle, Rect {}
    double area = switch (shape) { case Circle c -> …; case Rect r -> …; };
    
  • JDK: java.nio.file.FileVisitor(Files.walkFileTree), javax.lang.model.element.ElementVisitor(애너테이션 처리).

📌 5. 동시성 패턴 (Concurrency)

멀티스레드 환경의 자원·실행 제어. Java Concurrency in Practice 기반.

패턴의도Java 도구
Thread Pool스레드 재사용으로 생성비용·과생성 방지ExecutorService, ThreadPoolExecutor
Producer–Consumer생산·소비 속도 분리(버퍼)BlockingQueue
Future / Promise비동기 결과를 나중에 받기Future, CompletableFuture
Read–Write Lock읽기 동시 허용, 쓰기 배타ReentrantReadWriteLock, StampedLock
Double-Checked Locking지연 초기화 + 락 최소화volatile 필드 + 이중 검사
Thread-Local Storage스레드별 독립 상태ThreadLocal
Immutable Object공유해도 안전(상태 불변)record, final, List.of()
Guarded Suspension / Balking조건 충족까지 대기 / 즉시 포기wait/notify, Condition

모던 Java(21+) 동시성

  • 가상 스레드(Virtual Threads, JEP 444) — 경량 스레드. thread-per-request를 값싸게. Executors.newVirtualThreadPerTaskExecutor().
  • 구조적 동시성(Structured Concurrency) — 연관 작업을 한 단위로 묶어 취소·예외 전파. StructuredTaskScope.
  • 불변성 우선 — 가장 단순한 동시성 전략. 공유 + 불변 = 락 불필요.

📌 6. 안티패턴 & 리팩토링

6.1 대표 안티패턴

안티패턴증상처방
God Object / God Class한 클래스가 모든 책임SRP로 분리(Facade·Mediator)
Singleton 남용전역 상태·숨은 의존·테스트 곤란DI로 주입, 범위 제한
Anemic Domain Model데이터만 있고 행위는 서비스에도메인에 행위 부여
Spaghetti Code제어 흐름 뒤엉킴함수 추출·계층화
Golden Hammer한 패턴/도구를 모든 곳에문제에 맞는 도구 선택
Magic Number/String의미 불명 리터럴상수·enum화
Premature Optimization측정 없이 성급한 최적화먼저 측정(프로파일링)
Over-engineering불필요한 패턴 떡칠YAGNI — 필요할 때 도입

6.2 패턴으로 가는 리팩토링

  • 조건 분기 → 다형성 (Replace Conditional with Polymorphism) ⇒ Strategy / State
  • 거대 생성자 → Builder
  • 중복 알고리즘 골격 → Template Method
  • 인자 뭉치 → Introduce Parameter Object
  • 전역 변경 통지 → Observer

핵심 태도: 패턴은 목적이 아니라 수단. 문제(중복·경직·산탄총 수정)가 보일 때 처방으로 도입한다. — Refactoring (Fowler)


📌 7. 자주 헷갈리는 패턴 비교 ⭐ (실무에서 자주 혼동)

Strategy vs State

  • 구조 동일(상태/전략을 객체로 위임), 의도 다름.
  • Strategy외부 클라이언트가 알고리즘을 선택. 전략끼리 서로 모름.
  • State — 객체가 스스로 다음 상태로 전이. 상태끼리 전이를 앎.

Factory Method vs Abstract Factory

  • Factory Method상속 기반, 한 제품 생성을 하위 클래스가 결정.
  • Abstract Factory합성 기반, 제품 군(여러 종류) 을 일관되게 생성.

Adapter vs Bridge vs Decorator vs Proxy vs Facade

패턴핵심 의도인터페이스
Adapter안 맞는 걸 변환 (사후)다른 → 기대하는
Bridge추상·구현 분리 (사전 설계)두 축 독립
Decorator기능 추가같음 + 추가
Proxy접근 제어같음
Facade단순화 창구새 단순 인터페이스

Decorator·Proxy는 둘 다 같은 인터페이스로 감싸지만Decorator=기능, Proxy=통제.

Template Method vs Strategy

  • Template Method상속, 컴파일 타임 고정, 골격 일부만 교체.
  • Strategy합성, 런타임 통째 교체. (상속보다 합성 → 더 유연)

Observer vs Mediator vs Pub-Sub

  • Observer — Subject→Observer 단방향 통지 (직접 등록).
  • Mediator — 여러 객체의 양방향 통신을 중재자가 조정.
  • Pub-Sub — Observer 변형, 중간 브로커로 발행자-구독자 완전 분리.

Composite vs Decorator

  • Composite부분-전체 트리 (여러 자식).
  • Decorator한 겹씩 래핑 (자식 하나).

📌 8. Java 표준 라이브러리 패턴 빠른 표

"이 JDK 클래스 = 무슨 패턴?" 식별 문제 대비.

패턴JDK 적용 사례
SingletonRuntime.getRuntime(), Desktop.getDesktop()
Factory MethodCalendar.getInstance(), NumberFormat.getInstance(), valueOf()
Abstract FactoryDocumentBuilderFactory, TransformerFactory, XPathFactory
BuilderStringBuilder, Stream.Builder, HttpRequest.Builder, Locale.Builder
PrototypeObject.clone(), Cloneable
AdapterArrays.asList(), InputStreamReader, Collections.list()
BridgeJDBC Driver, AWT ComponentPeer
Compositejava.awt.Container, Swing JComponent, DOM Node
Decoratorjava.io(Buffered·Data·GZIP), Collections.unmodifiable/synchronized/checkedXxx
FlyweightInteger.valueOf()(캐시), Boolean.valueOf(), 문자열 풀
Proxyjava.lang.reflect.Proxy, RMI, Spring AOP
Chain of ResponsibilityServlet FilterChain, java.util.logging.Logger
CommandRunnable, Callable, Swing Action
Interpreterjava.util.regex.Pattern, java.text.Format
Iteratorjava.util.Iterator, Enumeration
ObserverPropertyChangeListener, Flow.Subscriber, Swing 리스너
StrategyComparator, RejectedExecutionHandler
Template MethodAbstractList/AbstractMap, InputStream.read(), HttpServlet.service()
VisitorFileVisitor(Files.walkFileTree), ElementVisitor

📌 9. 실무·프레임워크 적용 예시 ⭐

JDK API 너머, 실제 백엔드·프레임워크·도메인에서 패턴이 어떻게 쓰이는지.

생성 패턴

패턴실무 적용 사례
Singleton스프링 빈 기본 스코프(singleton), 앱 설정 레지스트리, DB 커넥션 풀, 캐시 매니저
Factory MethodLoggerFactory.getLogger()(SLF4J), JDBC DriverManager.getConnection(), 스프링 BeanFactory
Abstract Factory클라우드 SDK 추상화(AWS↔GCP 클라이언트 군), UI 테마(다크/라이트 위젯 세트), DB 방언별 객체 군
BuilderOkHttp Request.Builder, HttpRequest.newBuilder(), Lombok @Builder, 테스트 데이터 빌더, k8s 매니페스트 빌더
Prototype게임 엔티티 복제, 무거운 설정·문서 템플릿 복제, 표 셀 스타일 복사

구조 패턴

패턴실무 적용 사례
Adapter레거시 결제·인증 API를 신규 인터페이스로 통합, SLF4J↔Log4j/Logback 연결, 서드파티 SDK 래핑
Bridge결제 게이트웨이 추상화(PG사 교체 자유), 알림 발송(채널 × 메시지 종류), 크로스플랫폼 렌더링
CompositeReact/Vue 컴포넌트 트리, 파일시스템(폴더/파일), 조직도·메뉴·권한 트리
DecoratorHTTP 미들웨어/인터셉터 체인(인증·gzip·로깅), 스프링 HttpServletRequestWrapper, 커피 주문 토핑
Facade스프링 JdbcTemplate·RestTemplate, 결제·주문 모듈 단일 진입점, 복잡한 레거시 래핑
Flyweight게임 타일·파티클·스프라이트, 폰트 글리프 캐시, 에디터 문자 객체 공유
Proxy스프링 AOP @Transactional·@Cacheable·@Async, JPA/Hibernate 지연 로딩 프록시, API 레이트리밋·인증 프록시

행위 패턴

패턴실무 적용 사례
Chain of Responsibility스프링 시큐리티 필터 체인, 서블릿 필터, 미들웨어 파이프라인, 전자결재 승인 라인
Command메시지 큐 작업(Job), 에디터 undo/redo, 스케줄러 태스크, 이벤트 소싱 커맨드
InterpreterSQL·정규식 엔진, 규칙 엔진(Drools), 스프링 SpEL, 검색 쿼리 파서
Iterator컬렉션 순회, DB 커서·페이지네이션, Kafka consumer, 스트림 파이프라인
Mediator채팅 서버(참가자 중재), UI 폼 컴포넌트 조정, 메시지 브로커(개념), 항공 관제
MementoIDE/에디터 undo, 게임 세이브포인트, 폼 임시저장(draft), DB 스냅샷·롤백
Observer스프링 ApplicationEvent, 리액티브(Reactor·RxJava), 도메인 이벤트, 알림 구독, 실시간 대시보드
State주문 상태머신(결제→배송→완료), TCP 연결 상태, 워크플로/BPM 엔진, 게임 캐릭터 FSM
Strategy결제 수단(카드/간편결제/계좌), 할인·과금 정책, 압축·직렬화 선택, 로드밸런싱·라우팅 전략
Template Method스프링 JdbcTemplate(콜백 훅), 테스트 @BeforeEach/@AfterEach, 빌드·배포 파이프라인 단계
Visitor컴파일러·린터 AST 순회, 파일 트리 처리, 리포트·집계 생성기, 애너테이션 프로세서

동시성 패턴

패턴실무 적용 사례
Thread Pool웹서버 요청 처리, 스프링 @Async 실행기, 배치 워커 풀
Producer–Consumer로그 수집 버퍼, 이벤트 처리 큐, 이미지 처리 파이프라인
Future/Promise외부 API 병렬 호출, 비동기 집계(CompletableFuture.allOf)
ImmutableDTO·값 객체(record), 설정 스냅샷, 동시성 안전 공유 데이터

시나리오 → 패턴 빠른 선택

  • "기능을 런타임에 갈아끼우고 싶다" → Strategy
  • "상태에 따라 행동·전이가 다르다" → State
  • "요청 전후로 공통 처리를 끼우고 싶다" → Decorator / Chain of Responsibility
  • "복잡한 내부를 간단한 창구 하나로" → Facade
  • "변경을 여러 곳에 알리고 싶다" → Observer
  • "취소·재실행·큐잉이 필요하다" → Command

📌 10. 실무 노하우 — 현장에서 실제로 겪는 일

운영에서 디자인 패턴 때문에 실제로 터지거나 패턴으로 해결한 사례. 패턴 이름보다 왜 그렇게 되는지가 핵심이다.

1. SimpleDateFormat을 static으로 공유했다가 멀티스레드에서 깨진다 — 싱글톤/공유의 함정

  • SimpleDateFormat은 내부에 가변 상태가 있어 스레드 안전하지 않다. 전역 하나로 공유하면 동시 호출 시 파싱 결과가 뒤섞이거나 예외가 난다.
  • 노하우: 불변인 DateTimeFormatter(java.time)를 쓰거나, 불가피하면 ThreadLocal로 분리. 공유 싱글톤은 불변일 때만 안전하다.

2. @Transactional이 같은 클래스 내부 호출에서 안 먹힌다 — 프록시의 한계(self-invocation)

  • 스프링은 빈을 프록시로 감싸 트랜잭션을 적용하는데, 같은 객체의 this.method() 호출은 프록시를 거치지 않아 @Transactional·@Cacheable·@Async가 무시된다.
  • 노하우: 대상 메서드를 다른 빈으로 분리하거나 self-주입한 프록시로 호출. "애너테이션 붙였는데 왜 안 걸리지?"의 대부분이 이것.

3. ThreadLocal을 스레드 풀에서 안 비워 메모리 누수 — 스레드 재사용 함정

  • 톰캣 워커 스레드는 재사용된다. ThreadLocal에 담고 remove하지 않으면 값이 다음 요청으로 새거나, 재배포 시 클래스로더가 GC되지 못해 메모리가 계속 찬다(톰캣 경고 로그의 그 현상).
  • 노하우: try { set(...); ... } finally { threadLocal.remove(); } 를 습관화한다.

4. Integer 캐시 때문에 ==가 127까지만 true — 플라이웨이트 캐시

  • Integer.valueOf(127) == Integer.valueOf(127)은 true, 128부터 false. 작은 값에선 멀쩡하다 큰 값에서만 틀어지는 미궁 버그.
  • 노하우: 래퍼 값 비교는 항상 equals. 캐시는 성능용이지 동일성 보장이 아니다.

5. HashMap을 동시성 환경에서 공유해 CPU 100% 무한 루프 — 유명한 운영 장애(Java 7)

  • 여러 스레드가 동시에 resize하면 내부 링크가 꼬여 조회가 무한 루프에 빠졌다. Java 8에서 무한 루프는 완화됐지만 HashMap은 여전히 스레드 안전하지 않다.
  • 노하우: 공유 맵은 ConcurrentHashMap. "운영에서 가끔 한 코어만 100%"면 이걸 의심.

6. 단순 로직에 패턴 떡칠 → 유지보수 악몽 — 오버엔지니어링

  • FizzBuzzEnterpriseEdition(깃허브 풍자 프로젝트)처럼 20줄이면 될 코드를 팩토리·전략·비지터로 수십 클래스로 부풀린 현장이 흔하다.
  • 노하우: 패턴은 중복·변경 압력이 실제로 보일 때 도입(YAGNI). "나중에 바뀔 수도 있으니 미리"가 가장 비싼 핑계.

📌 11. 실무 데이터 — 외워두면 좋은 구체 사실

패턴이 실제 JDK·프레임워크에서 어떤 숫자·기본값·동작으로 나타나는지. (버전에 따라 달라질 수 있는 값은 표기)

주제구체 데이터
Flyweight — Integer 캐시기본 −128 ~ 127 공유. 상한은 -XX:AutoBoxCacheMax=N 또는 -Djava.lang.Integer.IntegerCache.high로 조정
Flyweight — String 풀문자열 리터럴은 String Pool에 자동 intern. 런타임 문자열은 String.intern()으로 명시 등록
Singleton — Spring 빈기본 스코프 singleton(컨테이너당 1개). prototype은 주입·조회마다 새 인스턴스
Proxy — Spring AOPjava.lang.reflect.Proxy인터페이스만 프록시 가능 → 클래스 프록시는 CGLIB/ByteBuddy. 스프링 AOP가 둘 다 사용
Observer — Observablejava.util.Observable/ObserverJava 9(2017)부터 @DeprecatedFlow·PropertyChangeListener로 대체
공유 가변 — 날짜 포맷SimpleDateFormat스레드 안전 X(javadoc 명시) / DateTimeFormatter불변·스레드 안전
Iterator — HashMap 내부기본 부하율 0.75, 한 버킷 8개 초과 + 용량 64 이상이면 트리(red-black)화, 6 이하로 줄면 리스트 복귀
Decorator — java.io 단축Files.newBufferedReader(path)BufferedReader+InputStreamReader+FileInputStream 3중첩을 대체
Strategy — Comparatorcomparing · thenComparing · reversed · nullsFirst/Last · naturalOrder로 합성
Builder — JDK 표준StringBuilder, Stream.builder(), HttpRequest.newBuilder()·HttpClient.newBuilder()(java.net.http, Java 11+), Locale.Builder
Abstract Factory — JAXPDocumentBuilderFactory·TransformerFactory·XPathFactorynewInstance()가 클래스패스 구현을 선택
Command — 동시성 APIRunnable(반환 없음)·Callable<V>(값·예외 반환)을 ExecutorService.submitFuture

모던 Java 변형 데이터

  • Visitorsealed + switch 패턴 매칭(JEP 441, Java 21)으로 망라성 컴파일 검사
  • Strategy/Command → 단일 메서드 함수형 인터페이스는 람다·메서드 참조로 대체
  • PrototypeCloneable/clone() 대신 복사 생성자(Effective Java Item 13)
  • Builderrecord(Java 16+)가 단순 값 객체의 보일러플레이트를 제거

📌 12. 암기 팁

23패턴 3분류

  • 생성(5)객체를 어떻게 만드나: 싱글톤·팩토리메서드·추상팩토리·빌더·프로토타입
  • 구조(7)객체를 어떻게 엮나: 어댑터·브리지·컴포지트·데코레이터·퍼사드·플라이웨이트·프록시
  • 행위(11)객체가 어떻게 소통·행동하나: 책임연쇄·커맨드·인터프리터·이터레이터·미디에이터·메멘토·옵저버·상태·전략·템플릿메서드·비지터

원리 한 줄

  • 변하는 것 ↔ 변하지 않는 것을 분리하라.
  • 상속보다 합성, 구현보다 인터페이스.
  • 패턴은 처방이지 목표가 아니다 — 과용은 안티패턴.

1차 자료: GoF Design Patterns (1994) · Head First Design Patterns (Java) · Effective Java 3e (Bloch) · Refactoring 2e (Fowler) · Refactoring.Guru · Java SE 21 API Docs.