1994년 출간된 GoF(Gang of Four)의 디자인 패턴은 객체지향 설계의 바이블과 같습니다. 하지만 30년이 지난 지금, 자바의 최신 버전이나 Kotlin, Go 같은 언어의 관점에서 보면 일부 패턴은 언어의 기본 기능에 흡수되었거나 오히려 독이 되기도 합니다. 현대적인 관점에서 여전히 유효한 GoF 패턴들을 정리해요

3가지 카테고리 요약

GoF 패턴은 목적에 따라 세 그룹으로 나뉩니다

분류 목적 대표 패턴
Creational (생성) 객체 생성 과정을 추상화 Factory, Builder, Singleton
Structural (구조) 클래스/객체를 조합해 더 큰 구조 형성 Adapter, Proxy, Decorator
Behavioral (행위) 객체 간의 책임 분담과 알고리즘 정의 Strategy, Observer, State

여전히 강력한 패턴들

현대적인 프레임워크(Spring, NestJS 등) 내부에서도 핵심적으로 쓰이는 패턴들입니다

1. 전략 패턴 (Strategy)

알고리즘을 클래스화하여 필요할 때마다 교체하는 방식입니다

  • 현대적 변화: 함수형 인터페이스나 람다(Lambda)를 지원하는 언어에서는 클래스 대신 함수를 직접 넘기는 방식으로 훨씬 간결하게 구현합니다

2. 어댑터 패턴 (Adapter)

서로 다른 인터페이스를 가진 두 객체를 연결합니다

  • 사례: 외부 타사 API의 데이터 형식을 우리 시스템의 내부 형식으로 변환할 때 필수적으로 쓰입니다

3. 관찰자 패턴 (Observer)

상태 변화를 여러 객체에게 전파합니다

  • 현대적 변화: 이벤트 주도 아키텍처(EDA)나 리액티브 프로그래밍(RxJS, Project Reactor)의 모태가 되는 패턴입니다

주의해야 할 패턴: 싱글톤 (Singleton)

GoF의 싱글톤 구현 방식은 현대적인 관점에서는 안티 패턴에 가깝습니다

  • 문제점: 전역 상태를 만들어 테스트를 어렵게 하고 결합도를 높입니다
  • 대안: 직접 싱글톤 클래스를 짜는 대신, 의존성 주입(DI) 컨테이너가 객체의 생명주기를 관리하게 하여 ‘싱글톤 범위(Scope)’로 사용하는 것이 정석입니다
핵심 인사이트: 패턴을 위한 코딩을 경계하세요
디자인 패턴은 목적이 아니라 수단입니다. "여기에 어떤 패턴을 쓸까?"를 먼저 고민하면 오버 엔지니어링(Over-engineering)에 빠지기 쉽습니다. 문제를 먼저 해결하고, 중복이 발생하거나 구조가 어지러워질 때 패턴을 도입하는 '리팩토링으로서의 패턴' 접근법이 필요합니다

정리

  • GoF 패턴은 객체지향 설계의 공통 언어를 제공합니다
  • Factory, Strategy, Observer는 현대 언어에서도 핵심적인 역할을 합니다
  • 언어 자체의 기능(람다, 일급 객체 함수)이 패턴을 대신할 수 있는지 먼저 확인하세요
  • 패턴의 이름보다 그 이면에 숨겨진 유연성과 확장성의 원리에 집중해야 합니다

다음 글에서는 도메인의 복잡성을 코드로 보호하는 DDD 전술 패턴에 대해 알아봐요