C++ Facade 패턴

복잡한 서브시스템에 단순화된 인터페이스를 제공합니다. 멀티미디어 시스템처럼 여러 복잡한 내부 모듈을 하나의 퍼사드로 감싸 사용자가 쉽게 접근할 수 있게 합니다.

Gist
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <stdexcept>

// ──────────────────────────────────────────────
// 서브시스템 클래스들: 각각 복잡한 내부 로직 보유
// 클라이언트는 이 클래스들을 직접 다루지 않아도 됨
// ──────────────────────────────────────────────
class AudioDecoder {
public:
    void loadCodec(const std::string& format) {
        std::cout << "  [AudioDecoder] " << format << " 코덱 로드 완료\n";
    }
    void setVolume(int level) {
        std::cout << "  [AudioDecoder] 볼륨 설정: " << level << "%\n";
    }
    void decode(const std::string& file) {
        std::cout << "  [AudioDecoder] 오디오 디코딩 중: " << file << "\n";
    }
    void release() {
        std::cout << "  [AudioDecoder] 코덱 자원 해제\n";
    }
};

class VideoDecoder {
public:
    void initialize(int width, int height) {
        std::cout << "  [VideoDecoder] 해상도 초기화: "
                  << width << "x" << height << "\n";
    }
    void loadCodec(const std::string& format) {
        std::cout << "  [VideoDecoder] " << format << " 코덱 로드 완료\n";
    }
    void decode(const std::string& file) {
        std::cout << "  [VideoDecoder] 비디오 디코딩 중: " << file << "\n";
    }
    void release() {
        std::cout << "  [VideoDecoder] 코덱 자원 해제\n";
    }
};

class DisplayManager {
public:
    void setResolution(int width, int height) {
        std::cout << "  [DisplayManager] 디스플레이 해상도: "
                  << width << "x" << height << "\n";
    }
    void setFullscreen(bool enabled) {
        std::cout << "  [DisplayManager] 전체화면: "
                  << (enabled ? "활성화" : "비활성화") << "\n";
    }
    void render() {
        std::cout << "  [DisplayManager] 프레임 렌더링 중...\n";
    }
    void close() {
        std::cout << "  [DisplayManager] 디스플레이 종료\n";
    }
};

class NetworkStream {
public:
    bool connect(const std::string& url) {
        std::cout << "  [NetworkStream] 스트림 연결: " << url << "\n";
        return true; // 실제에선 연결 실패 처리 필요
    }
    std::string fetchMetadata() {
        return R"({"title":"샘플 영상","format":"mp4","bitrate":"4Mbps"})";
    }
    void disconnect() {
        std::cout << "  [NetworkStream] 스트림 연결 해제\n";
    }
};

class SubtitleEngine {
public:
    void loadSubtitle(const std::string& lang) {
        std::cout << "  [SubtitleEngine] 자막 로드: " << lang << "\n";
    }
    void render(int timestamp) {
        std::cout << "  [SubtitleEngine] 자막 렌더링 (t=" << timestamp << "ms)\n";
    }
    void unload() {
        std::cout << "  [SubtitleEngine] 자막 언로드\n";
    }
};

// ──────────────────────────────────────────────
// 퍼사드: 복잡한 멀티미디어 서브시스템을 단순한 API로 노출
// ──────────────────────────────────────────────
class MediaPlayerFacade {
public:
    MediaPlayerFacade()
        : audio_(std::make_unique<AudioDecoder>())
        , video_(std::make_unique<VideoDecoder>())
        , display_(std::make_unique<DisplayManager>())
        , network_(std::make_unique<NetworkStream>())
        , subtitle_(std::make_unique<SubtitleEngine>()) {}

    // 온라인 스트리밍 재생 (복잡한 초기화 과정을 하나의 메서드로)
    void playStream(const std::string& url, const std::string& subtitleLang = "ko") {
        std::cout << "\n[MediaPlayerFacade] 스트림 재생 시작: " << url << "\n";

        // 1. 네트워크 연결 및 메타데이터 획득
        if (!network_->connect(url)) {
            throw std::runtime_error("스트림 연결 실패: " + url);
        }
        const auto meta = network_->fetchMetadata();
        std::cout << "  [MediaPlayerFacade] 메타데이터: " << meta << "\n";

        // 2. 디코더 초기화
        video_->initialize(1920, 1080);
        video_->loadCodec("H.264");
        audio_->loadCodec("AAC");
        audio_->setVolume(80);

        // 3. 디스플레이 설정
        display_->setResolution(1920, 1080);
        display_->setFullscreen(true);

        // 4. 자막 로드
        subtitle_->loadSubtitle(subtitleLang);

        // 5. 재생
        video_->decode(url);
        audio_->decode(url);
        display_->render();
        subtitle_->render(0);

        std::cout << "[MediaPlayerFacade] ▶ 재생 중...\n";
    }

    // 로컬 파일 재생
    void playFile(const std::string& filePath) {
        std::cout << "\n[MediaPlayerFacade] 로컬 파일 재생: " << filePath << "\n";
        video_->initialize(1280, 720);
        video_->loadCodec("H.265");
        audio_->loadCodec("MP3");
        audio_->setVolume(70);
        display_->setResolution(1280, 720);
        display_->setFullscreen(false);
        video_->decode(filePath);
        audio_->decode(filePath);
        display_->render();
        std::cout << "[MediaPlayerFacade] ▶ 재생 중...\n";
    }

    // 재생 중단 및 자원 정리
    void stop() {
        std::cout << "\n[MediaPlayerFacade] 재생 중단 및 자원 정리\n";
        subtitle_->unload();
        audio_->release();
        video_->release();
        display_->close();
        network_->disconnect();
        std::cout << "[MediaPlayerFacade] ■ 정지 완료\n";
    }

private:
    std::unique_ptr<AudioDecoder>   audio_;
    std::unique_ptr<VideoDecoder>   video_;
    std::unique_ptr<DisplayManager> display_;
    std::unique_ptr<NetworkStream>  network_;
    std::unique_ptr<SubtitleEngine> subtitle_;
};

// ──────────────────────────────────────────────
// 사용 예시
// ──────────────────────────────────────────────
int main() {
    std::cout << "=== 멀티미디어 플레이어 (Facade 패턴) ===\n";

    MediaPlayerFacade player;

    // 클라이언트는 복잡한 서브시스템 세부사항을 알 필요 없음
    player.playStream("https://cdn.example.com/video/sample.mp4", "ko");
    player.stop();

    std::cout << "\n--- 로컬 파일 재생 ---";
    MediaPlayerFacade localPlayer;
    localPlayer.playFile("/videos/movie.mkv");
    localPlayer.stop();

    return 0;
}