GoF 디자인 패턴 in Larman (Ch 23)
Iteration 2에서 외부 서비스 연동, 다양한 결제 방식, 복잡한 가격 정책 같은 문제가 등장한다. 이때 07-grasp-patterns|GRASP의 기본 원칙만으로는 설계를 표현하기 부족해지면서 GoF 패턴이 필요해진다. 하지만 GoF 패턴을 GRASP의 조합으로 분석할 수 있다는 점을 기억하자 — 별개가 아니라 더 구체적인 레시피다.
핵심 패턴 6개
Adapter
문제: 외부 시스템(세금 계산기, 회계 시스템 등)마다 API가 다르다. 변경할 수도 없다. 해법: 중간 어댑터 객체를 두고, 내부에서는 통일된 인터페이스로만 통신한다.
ITaxCalculatorAdapter (인터페이스)
├─ TaxMasterAdapter
└─ GoodAsGoldTaxProAdapter
GRASP로 보면: Polymorphism + Indirection + Protected Variations의 조합.
Factory
문제: 어댑터를 누가 생성하나? 도메인 객체(Register)가 만들면 관심사가 섞인다.
해법: ServicesFactory라는 Pure Fabrication을 만들어 생성 책임을 분리한다.
Factory의 핵심 트릭: 클래스 이름을 외부 설정(프로퍼티 파일 등)에서 읽어 동적으로 로딩한다. 이러면 코드 변경 없이 어댑터를 교체할 수 있다.
Singleton
문제: ServicesFactory 인스턴스가 하나만 있어야 한다. 해법: 전역 접근점을 제공하되, 인스턴스를 하나로 제한한다.
Larman은 static 메서드 대신 인스턴스 메서드를 사용하는 Singleton을 권한다 — 나중에 remote-enabling이나 다중 인스턴스로 전환이 쉽기 때문.
Strategy
문제: 가격 정책(할인율, 시니어 할인, 당일 할인 등)이 다양하고 런타임에 바뀔 수 있다. 해법: 가격 계산 알고리즘을 인터페이스로 추출하고, 각 정책을 별도 클래스로 구현한다.
ISalePricingStrategy (인터페이스)
├─ PercentDiscountPricingStrategy
├─ AbsoluteDiscountPricingStrategy
└─ NoDiscountPricingStrategy
Sale 객체는 ISalePricingStrategy만 알고 있고, 구체적인 정책은 모른다.
Composite
문제: 여러 할인 정책을 동시에 적용해야 한다 (예: 시니어 할인 + 당일 할인). 해법: Composite 패턴으로 정책들을 트리 구조로 합성한다. CompositePricingStrategy가 여러 ISalePricingStrategy를 담고, 최우선/합산 등의 전략으로 결합한다.
Facade
문제: 서브시스템의 여러 객체를 외부에서 직접 다루면 결합도가 높아진다. 해법: 서브시스템의 진입점 역할을 하는 하나의 Facade 객체를 제공한다.
Observer (Publish-Subscribe)
문제: Sale의 총액이 바뀔 때 UI를 갱신해야 하는데, 도메인 객체가 UI를 직접 알면 Model-View Separation이 깨진다. 해법: Sale이 이벤트를 발행하고, UI가 구독한다. Sale은 구독자가 누구인지 모른다.
패턴 조합의 실전 예시
외부 서비스 연동 문제를 한 문장으로 표현하면:
"Adapter를 Singleton Factory에서 생성하여 Protected Variations를 달성한다."
이 문장 하나에 Adapter, Factory, Singleton, Protected Variations, Polymorphism, Indirection이 전부 담겨 있다. 패턴 이름이 공유 어휘가 되면 소통이 이렇게 압축된다.
바이브 코딩에서의 활용
GoF 패턴 이름은 LLM이 매우 잘 이해하는 어휘다. 패턴 이름 + 적용 대상을 명시하면 된다.
프롬프트 예시:
"외부 결제 서비스 연동을 설계해줘.
패턴 적용:
1. Adapter: IPaymentGateway 인터페이스를 정의하고,
StripeAdapter, TossAdapter가 구현한다
2. Factory: PaymentGatewayFactory가 환경 설정에서 어댑터 클래스를 읽어 동적 생성한다
3. Singleton: Factory는 싱글턴으로 관리한다
4. Strategy: 가격 할인 정책은 IDiscountStrategy 인터페이스로 분리하고,
PercentDiscount, FixedDiscount, CompositeDiscount를 구현한다
도메인 객체(Order)는 인터페이스만 알고, 구체 구현체는 모르게 해줘."