ice rabbit programming

[C++] GoF 패턴 간단 정리(2) - 간접층의 원리, 행동 패턴 본문

Development/C++

[C++] GoF 패턴 간단 정리(2) - 간접층의 원리, 행동 패턴

판교토끼 2026. 7. 16. 22:34
728x90

간접층의 원리를 활용한 패턴들

간접층을 도입하여 의존성을 제어하며, 목적에 따라 아래와 같이 나뉜다.

  • Adapter 패턴: 기존 클래스의 인터페이스가 요구 사항과 맞지 않을 때 인터페이스를 변경(호환성 제공)하기 위해 사용한다.
    • Class Adapter: 다중 상속 또는 값으로 포함하여 수정.
    • Object Adapter: 객체를 포인터/참조로 포함(Composition)하여 수정. STL의 std::stack 및 std::reverse_iterator가 이에 해당한다.
  • Proxy 패턴: 특정 객체에 대한 접근을 제어하거나 대행하기 위해 대리 객체를 제공한다. (예: Remote Proxy, Virtual Proxy, Protected Proxy).
  • Facade 패턴: 복잡한 서브시스템 구조의 의존성을 감추고, 호출하기 단순한 단일 포괄 인터페이스를 제공한다.
  • Bridge 및 PIMPL Idiom: 구현부(Implementation)와 추상화(Abstraction) 개념을 분리하여 각각 독립적으로 확장할 수 있도록 설계한다.
    • PIMPL (Pointer to IMPLementation): 헤더 파일에 전방 선언(Forward Declaration)만 남기고 상세 구현체 클래스는 소스 파일(.cpp)로 완전히 격리하여 컴파일 속도를 향상시키고 정보 은닉을 제공하는 C++ 핵심 기법이다.

행동 패턴 (Behavioral Patterns)

  • State 패턴: 객체의 내부 상태에 따라 스스로 행동을 변경할 수 있도록 유도한다. 조건에 따른 if-else 분기 처리를 상태 클래스로 분리해 내어 OCP를 극대화한다.
  • Observer 패턴: 1:N 종속 관계를 정의하여 Subject의 상태가 변할 때 등록된 모든 Observer 객체들에게 자동으로 변경을 통보한다. 데이터를 함께 보내는 Push 방식과, 통보 후 옵저버가 직접 조회하는 Pull 방식이 존재하며 일반적으로 느슨한 결합도를 유지할 수 있는 Pull 방식이 더 선호된다.
  • Visitor 패턴: 객체 구조를 변경하지 않고도, 내부 요소들을 순회하며 새로운 기능(오퍼레이션)을 손쉽게 정의할 수 있도록 설계된 패턴이다. accept와 visit 함수를 통한 이중 디스패치(Double Dispatch) 메커니즘을 사용한다. 타입을 추가하기는 어려우나 함수를 추가하기는 매우 쉽다.

Menu Event 처리 (C++ 표준 라이브러리 활용)

과거에는 가상 함수 기반의 리스너(Listener) 객체나 커스텀 함수 래퍼 클래스를 직접 구현했으나, 모던 C++(C++11~) 환경에서는 표준 라이브러리 <functional>의 std::function을 사용하여 일관된 함수 바인딩 인터페이스를 구축한다.

#include <iostream>
#include <functional>

void Foo() {
  std::cout << "Foo called\n";
}

class Dialog {
 public:
  void Close() {
    std::cout << "Dialog closed\n";
  }
};

int main() {
  // std::function을 활용한 호출 인터페이스 통일
  std::function<void()> f;
  
  f = &Foo; 
  f(); 
  
  Dialog dlg;
  // 기존 std::bind 방식
  f = std::bind(&Dialog::Close, &dlg);
  f(); 
  
  // 모던 C++14/17 권장 방식: std::bind 대신 람다 캡처를 활용
  // 가독성이 높고 컴파일러 최적화 효율이 우수하다.
  f = [&dlg]() { 
    dlg.Close(); 
  };
  f();
  
  return 0;
}
728x90