빠른 참조 — 어디서 무엇이 쓰이나
앞 편들이 "왜·어떻게" 였다면 이 편은 찾아보는 용도다. "이 JDK 클래스가 무슨 패턴인가", "이 상황에 무슨 패턴인가", 그리고 외워 두면 유용한 구체 수치.
JDK 에서 패턴 찾기
식별 문제로 자주 나오는 것들이다. 왜 그 패턴인지를 한 줄로 붙였다.
| 패턴 | JDK 사례 | 왜 그 패턴인가 |
|---|---|---|
| Singleton | Runtime.getRuntime() | JVM 당 하나가 본질 |
| Factory Method | Calendar.getInstance() | 로케일에 따라 구현을 고른다 |
connection.createStatement() | 드라이버가 구현을 정한다 | |
| Abstract Factory | DocumentBuilderFactory.newInstance() | 파서 한 벌을 통째로 |
| Builder | HttpRequest.newBuilder() | 선택 항목이 많은 객체를 단계별 조립 |
| Prototype | Object.clone() | 복제로 생성 (권장하지는 않음) |
| Adapter | Arrays.asList(arr) | 배열을 List 로 보이게 |
new InputStreamReader(in) | 바이트 → 문자 | |
| Bridge | JDBC API ↔ 드라이버 | 두 축이 독립적으로 변한다 |
| Composite | java.awt.Container | Component 를 담는 Component |
| Decorator | new BufferedInputStream(in) | 같은 인터페이스로 겹겹이 |
Collections.unmodifiableList() | 쓰기를 막는 겹을 한 장 | |
| Facade | Files.newBufferedReader(path) | 3중첩 조립을 한 줄로 |
| Flyweight | Integer.valueOf(n) | −128~127 을 공유 |
| Proxy | java.lang.reflect.Proxy | 같은 인터페이스로 호출을 가로챈다 |
| CoR | Filter / FilterChain | 다음으로 넘기는 사슬 |
| Command | Runnable · Callable | 할 일을 객체로 |
| Interpreter | Pattern.compile() | 문법을 해석 구조로 |
| Iterator | Iterator · for-each | 내부 표현을 숨긴 순회 |
| Observer | Flow.Publisher / Subscriber | 1:N 통지 |
| Strategy | Comparator | 알고리즘을 인자로 |
| Template Method | AbstractList | get·size 만 구현하면 나머지가 동작 |
| Visitor | FileVisitor (Files.walkFileTree) | 구조는 두고 연산만 |
실무 적용 지도
생성
| 패턴 | 실무에서 |
|---|---|
| Singleton | 스프링 빈 기본 스코프, 커넥션 풀, 캐시 매니저 |
| Factory Method | LoggerFactory.getLogger(), DriverManager.getConnection() |
| Abstract Factory | 클라우드 SDK 추상화(AWS↔GCP 한 벌), DB 방언별 객체 군 |
| Builder | Request.Builder(OkHttp), Lombok @Builder, 테스트 데이터 빌더 |
| Prototype | 무거운 기본 설정을 복제해 일부만 변경 |
구조
| 패턴 | 실무에서 |
|---|---|
| Adapter | PG·인증 등 외부 SDK 를 우리 인터페이스로, SLF4J ↔ 구현체 |
| Bridge | 결제 게이트웨이 추상화(PG 교체), 알림(채널 × 종류) |
| Composite | 메뉴·조직도·권한 트리, 댓글 스레드 |
| Decorator | 인터셉터 체인, HttpServletRequestWrapper, Resilience4j |
| Facade | JdbcTemplate·RestTemplate, 주문 흐름 단일 진입점 |
| Flyweight | 코드 마스터 캐시, 대량 파싱 시 반복 토큰 |
| Proxy | @Transactional·@Cacheable·@Async, JPA 지연 로딩 |
행위
| 패턴 | 실무에서 |
|---|---|
| CoR | 스프링 시큐리티 필터 체인, 서블릿 필터, 전자결재 승인 라인 |
| Command | 메시지 큐 작업, 스케줄러 태스크, 이벤트 소싱 |
| Interpreter | SpEL, 규칙 엔진, 검색 쿼리 파서, 쿠폰 조건식 |
| Iterator | DB 커서·페이지네이션, Kafka consumer |
| Mediator | 채팅방, 주문 흐름 조정, 메시지 브로커(개념) |
| Memento | 폼 임시저장, 배포 롤백 스냅샷, 설정 이력 |
| Observer | 스프링 ApplicationEvent, 도메인 이벤트, 리액티브 |
| State | 주문 상태 기계, 결제·배송 흐름, 워크플로 승인 |
| Strategy | 결제 수단, 할인·과금 정책, 배송비 계산, 라우팅 |
| Template Method | JdbcTemplate 콜백, 배치 스텝, 배포 파이프라인 단계 |
| Visitor | AST 순회(린터·컴파일러), 리포트 집계, 애너테이션 프로세서 |
상황에서 패턴 고르기
실무에서 실제로 던지는 질문 형태로 적었다.
| 이런 상황 | 이 패턴 |
|---|---|
| "결제 수단이 계속 늘어난다" | Strategy (enum 전략 또는 스프링 List 주입) |
| "주문이 어떤 상태에서 어떤 상태로 갈 수 있는지 코드에 안 보인다" | State |
| "요청 전후로 공통 처리(인증·로깅·추적)를 끼우고 싶다" | CoR(끊을 수 있음) / Decorator(기능 추가) |
| "외부 SDK 를 여러 곳에서 직접 부른다. 교체하려니 다 고쳐야 한다" | Adapter — 우리 인터페이스로 감싼다 |
| "PG 사를 갈아 끼울 수 있어야 한다" | Bridge — 설계 단계에서 축을 나눈다 |
| "주문 하나 넣는 코드가 컨트롤러마다 복사돼 있다" | Facade |
| "주문 뒤에 해야 할 일(적립·통계·알림)이 계속 는다" | Observer (스프링 이벤트) |
| "작업을 나중에·다른 서버에서 실행해야 한다" | Command (큐에 넣는다) |
| "되돌리기가 필요하다" | 반대 동작이 명확하면 Command.undo, 아니면 Memento |
| "쿠폰 조건을 배포 없이 바꾸고 싶다" | Interpreter — 규칙을 데이터로 |
| "생성자 인자가 8개고 순서를 헷갈린다" | Builder |
| "AWS 와 GCP 클라이언트가 섞이면 안 된다" | Abstract Factory |
| "흐름은 같은데 한 단계만 다른 클래스가 여럿" | Template Method(상속) 또는 콜백 |
외워 두면 유용한 구체 수치
| 주제 | 값 | 왜 중요한가 |
|---|---|---|
| Integer 캐시 | −128 ~ 127 | == 가 이 범위에서만 true. -XX:AutoBoxCacheMax 로 상한 조정 가능 |
| 문자열 풀 | 리터럴은 자동 인터닝 | new String("a") != "a", .intern() 으로 풀에서 가져옴 |
| 스프링 빈 기본 스코프 | singleton (컨테이너당 1개) | 필드에 가변 상태를 두면 요청끼리 섞인다 |
| 스프링 AOP 프록시 | 인터페이스 있으면 JDK, 없으면 CGLIB | final 클래스·메서드는 프록시 불가 |
SimpleDateFormat | 스레드 안전 아님(javadoc 명시) | DateTimeFormatter 는 불변·안전 |
java.util.Observable | Java 9 부터 deprecated | 순서 보장 없음, 타입 안전하지 않음 → Flow |
| HashMap 트리화 | 버킷 8개 초과 + 용량 64 이상, 6 이하면 리스트 복귀 | 기본 부하율 0.75 |
Executors.newFixedThreadPool | 큐가 무제한 | 거부 정책 전에 OOM 이 온다 |
ForkJoinPool.commonPool | 코어 수 − 1 | CompletableFuture 기본 실행기. 블로킹 I/O 금지 |
Files.newBufferedReader | 3중첩 대체 | BufferedReader+InputStreamReader+FileInputStream |
모던 자바가 바꾼 것들
| 패턴 | 대체 |
|---|---|
| Visitor | sealed + switch 패턴 매칭 (JEP 441, Java 21) — 망라성을 컴파일러가 검사 |
| Strategy / Command | 단일 메서드면 람다·메서드 참조 |
| Prototype | Cloneable 대신 복사 생성자 (Effective Java Item 13) |
| Builder | 단순 값 객체는 record (Java 16+) |
| Singleton | 직접 구현 대신 컨테이너 빈 |
| Observer | Observable 대신 Flow(역압 지원) 또는 스프링 이벤트 |
| Thread Pool | 가상 스레드가 "스레드는 비싸다" 는 전제를 바꿨다 |
23패턴 분류
- 생성 5 — 객체를 어떻게 만드나 싱글톤 · 팩토리메서드 · 추상팩토리 · 빌더 · 프로토타입
- 구조 7 — 객체를 어떻게 엮나 어댑터 · 브리지 · 컴포지트 · 데코레이터 · 퍼사드 · 플라이웨이트 · 프록시
- 행위 11 — 객체가 어떻게 소통·행동하나 책임연쇄 · 커맨드 · 인터프리터 · 이터레이터 · 미디에이터 · 메멘토 · 옵저버 · 상태 · 전략 · 템플릿메서드 · 비지터
원리 한 줄
출처 — GoF Design Patterns(1994) · Effective Java 3e(Bloch) · Refactoring 2e(Fowler) · Java SE 21 API Docs · JEP 441(Pattern Matching for switch) · JEP 444(Virtual Threads)