GoF 디자인 패턴을 설계 선택에 활용하는 방법

GoF 디자인 패턴의 생성·구조·행위 분류와 전자상거래 적용 사례, 아키텍처 스타일과의 차이를 실무 설계 관점에서 설명한다.

2026-08-14 · 최초 발행 2025-05-23

반복되는 설계 문제를 다루는 공통 언어

디자인 패턴은 소프트웨어 설계에서 계속 나타나는 문제에 대한 검증된 해결책을 모아 둔 것이다. 객체지향 프로그래밍에서 클래스와 객체가 어떻게 협력할지를 정리하고, 재사용 가능한 설계를 만들기 위한 설계 기술로 쓰인다.

1994년 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 네 저자가 출판한 Design Patterns: Elements of Reusable Object-Oriented Software를 통해 널리 알려졌다. 개발자들이 설계 의도를 더 쉽게 공유하고, 유사한 문제에서 이미 검토된 해법을 활용하게 한다.

GoF는 23개 패턴을 생성, 구조, 행위 패턴으로 나눴다.

객체 생성의 선택지를 분리하는 생성 패턴

생성 패턴은 객체를 만드는 메커니즘을 다룬다. 생성 로직을 캡슐화해 시스템이 어떤 객체를 만들고 조합할지 유연하게 바꿀 수 있도록 한다.

생성 패턴싱글톤Singleton팩토리 메소드Factory Method추상 팩토리Abstract Factory빌더Builder프로토타입Prototype

싱글톤은 클래스 인스턴스가 하나만 생성되도록 보장한다. 데이터베이스 연결이나 로깅 클래스에 활용할 수 있다.

public class DatabaseConnection {
    private static DatabaseConnection instance;

    private DatabaseConnection() {
        // 생성자는 private으로 외부에서 접근 불가
    }

    public static synchronized DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
}

팩토리 메소드는 객체 생성을 서브클래스에 맡기는 방식이다. 어느 클래스를 인스턴스화할지는 런타임에 결정할 수 있다.

인터페이스와 객체를 조합하는 구조 패턴

구조 패턴은 클래스와 객체를 더 큰 구조로 결합하는 방법에 집중한다. 서로 다른 인터페이스를 가진 클래스도 함께 동작하도록 만들 때 사용한다.

구조 패턴어댑터Adapter브리지Bridge컴포지트Composite데코레이터Decorator퍼사드Facade플라이웨이트Flyweight프록시Proxy

어댑터는 호환되지 않는 인터페이스를 변환해 함께 동작하게 한다. 레거시 시스템을 새 시스템에 통합할 때 유용하다.

컴포지트는 객체를 트리 구조로 구성해 부분과 전체의 계층을 표현한다. 파일 시스템 구조나 UI 컴포넌트를 구조화할 때 활용할 수 있다.

객체 사이의 책임을 배치하는 행위 패턴

행위 패턴은 객체 간 상호작용과 책임 분배를 다룬다. 알고리즘과 객체별 책임을 어떻게 배치할지 정의하는 데 초점이 있다.

행위 패턴책임 연쇄Chain of Responsibility커맨드Command인터프리터Interpreter이터레이터Iterator중재자Mediator메멘토Memento옵저버Observer상태State전략Strategy템플릿 메소드Template Method방문자Visitor

옵저버는 객체 사이에 일대다 의존성을 설정해 한 객체의 상태 변화가 다른 객체들에게 전달되게 한다. 이벤트 처리 시스템과 MVC 아키텍처의 모델-뷰 관계에 활용된다.

전략은 알고리즘군을 정의하고 각각을 캡슐화해 교체 가능하게 만든다. 정렬 알고리즘이나 결제 방법처럼 여러 구현 전략 중 하나를 선택해야 할 때 쓸 수 있다.

전자상거래 흐름에 패턴을 배치하는 예

전자상거래 시스템에서는 데이터베이스 연결 관리에 싱글톤 패턴을, 신용카드·계좌이체·페이팔처럼 여러 결제 방식의 객체 생성에 팩토리 메소드 패턴을 적용할 수 있다. 주문 상태 변경 후 고객에게 알림을 보내는 흐름에는 옵저버 패턴이, 할인 정책 선택에는 전략 패턴이 맞는다. 포장, 선물, 보험 같은 추가 서비스를 주문에 붙일 때는 데코레이터 패턴을 사용할 수 있다.

NotificationObserverPaymentStrategyOrderOrderFactoryClientNotificationObserverPaymentStrategyOrderOrderFactoryClientcreateOrder()new Order()setPaymentStrategy(CreditCardPayment)addObserver(EmailNotification)checkout()pay()notify()

시스템 구조를 정하는 아키텍처 스타일과의 차이

특성 디자인 패턴 아키텍처 스타일
범위 클래스와 객체 수준의 미시적 설계 시스템 전체 구조의 거시적 설계
목적 특정 문제 해결을 위한 클래스 설계 시스템의 전체적인 구조와 속성 결정
예시 싱글톤, 팩토리, 옵저버 등 클라이언트-서버, 마이크로서비스, MVC 등
적용 단위 주로 단일 컴포넌트 내부 컴포넌트 간의 관계와 상호작용
추상화 수준 상대적으로 낮은 수준 높은 수준의 추상화

디자인 패턴은 컴포넌트 내부의 설계 문제를 다루는 반면, 아키텍처 스타일은 시스템 전체의 구조와 컴포넌트 간 관계를 결정한다.

패턴이 주는 이점과 비용

검증된 해결책을 활용하면 개발 시간을 줄일 수 있고, 코드의 재사용성과 유지보수성을 높이는 데 도움이 된다. 설계 의도를 공유하는 공통 언어가 생기며, 객체지향 설계 원칙을 따르고 확장 가능한 시스템을 구성하기도 쉬워진다.

반대로 패턴을 과도하게 적용하면 불필요한 복잡성이 늘어난다. 처음 익히는 비용이 있고, 패턴 자체에 매달리다 문제의 본질을 놓칠 수 있다. 적용 방식에 따라 성능 오버헤드가 생길 가능성도 있다.

패턴보다 먼저 확인할 설계 조건

패턴을 선택하기 전에 해결하려는 문제를 정확히 이해해야 한다. YAGNI(You Aren't Gonna Need It) 원칙처럼 필요해졌을 때 적용하고, KISS(Keep It Simple, Stupid) 원칙에 따라 더 단순한 해법이 있다면 복잡한 패턴을 피하는 편이 낫다.

프로젝트의 맥락에 해당 패턴이 맞는지도 검토해야 한다. 필요에 따라 여러 패턴을 조합해 더 강력한 해법을 구성할 수 있지만, 조합 자체가 목적이 되어서는 안 된다.

개발 패러다임이 바꾸는 패턴의 쓰임

함수형 프로그래밍이 부상하면서 전통적인 GoF 패턴 일부의 중요성은 줄어들었다. 마이크로서비스 아키텍처에서는 시스템 간 통신 패턴이 중요해졌고, Circuit Breaker와 Bulkhead 같은 패턴이 언급된다.

리액티브 프로그래밍에서는 옵저버 패턴이 기본 구조로 활용된다. 클라우드 네이티브 환경에서는 탄력성과 회복력에 관련된 패턴의 비중이 커진다. 기본 원리는 유지되지만, 개발 환경에 맞춘 확장과 변형도 계속 이뤄지고 있다.

디자인 패턴GoF객체지향 설계소프트웨어 아키텍처재사용성