research

GoF 디자인 패턴 in Larman (Ch 23)

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)는 인터페이스만 알고, 구체 구현체는 모르게 해줘."