Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 복합(Composite) 디자인 패턴 완벽 정리: 개념, 구조, 예제 코드

복합(Composite) 패턴은 여러 개의 객체를 마치 하나의 객체처럼 동일한 방식으로 다루어야 할 때 사용하는 대표적인 구조적(structural) 디자인 패턴입니다. 이 패턴은 객체들을 트리(tree) 구조로 구성하여, 개별 객체(부분)와 객체들의 집합(전체)을 하나의 계층 구조로 일관성 있게 표현할 수 있게 해줍니다.

복합 패턴은 자기 자신과 동일한 타입의 객체들을 담는 클래스를 생성합니다. 이 클래스는 내부에 포함된 객체 그룹을 추가하거나 삭제·수정할 수 있는 방법을 제공하며, 클라이언트는 단일 객체와 복합 객체를 구분하지 않고 동일한 인터페이스로 사용할 수 있다는 점이 가장 큰 장점입니다.

복합 패턴의 주요 구성 요소

  • Component(컴포넌트): 리프와 복합 객체가 공통으로 구현하는 추상 인터페이스 또는 기반 클래스입니다.
  • Leaf(리프): 더 이상 하위 요소를 가지지 않는 말단 객체로, 실제 작업을 수행합니다.
  • Composite(복합체): 하위 컴포넌트들을 저장하고 관리하며, 요청받은 연산을 자식 객체들에게 전달(위임)하는 역할을 합니다.

예제로 이해하는 복합 패턴

복합 패턴은 조직의 직원 계층 구조, 파일 시스템, GUI 위젯 트리처럼 '부분-전체' 계층을 표현해야 하는 상황에서 특히 유용합니다. 아래 예제에서는 개별 문서 페이지를 나타내는 Page(리프) 클래스와, 여러 페이지를 하나로 묶어 관리하는 Copy(복합체) 클래스를 통해 패턴의 동작 방식을 살펴봅니다.

클래스 다이어그램을 보면 PageObject라는 공통 인터페이스를 Page(리프)와 Copy(복합체)가 모두 구현하고 있습니다. 여기서 핵심은 Copy 클래스가 내부적으로 PageObject 객체들을 포함(composition)하고 있다는 점으로, 이것이 바로 복합 패턴의 본질입니다.

예제 코드

#include <iostream>
#include <vector>
using namespace std;

class PageObject {
    public:
        virtual void addItem(PageObject a) { }
        virtual void removeItem() { }
        virtual void deleteItem(PageObject a) { }
};

class Page : public PageObject {
    public:
        void addItem(PageObject a) {
            cout << "Item added into the page" << endl;
        }
        void removeItem() {
            cout << "Item Removed from page" << endl;
        }
        void deleteItem(PageObject a) {
            cout << "Item Deleted from Page" << endl;
        }
};

class Copy : public PageObject {
    vector<PageObject> copyPages;
    public:
        void AddElement(PageObject a) {
            copyPages.push_back(a);
        }
        void addItem(PageObject a) {
            cout << "Item added to the copy" << endl;
        }
        void removeItem() {
            cout << "Item removed from the copy" << endl;
        }
        void deleteItem(PageObject a) {
            cout << "Item deleted from the copy";
        }
};

int main() {
    Page p1;
    Page p2;
    Copy myCopy;
    myCopy.AddElement(p1);
    myCopy.AddElement(p2);
    myCopy.addItem(p1);
    p1.addItem(p2);
    myCopy.removeItem();
    p2.removeItem();
}

실행 결과

Item added to the copy
Item added into the page
Item removed from the copy
Item Removed from page

코드 설명

PageObject는 모든 객체가 공유하는 추상 기반 클래스로, addItem, removeItem, deleteItem 가상 함수를 선언합니다. Page 클래스는 리프 역할을 하며 각 연산이 호출될 때 해당 메시지를 출력합니다. 반면 Copy 클래스는 복합체 역할을 하며, vector<PageObject> 컨테이너로 여러 페이지 객체를 보관하고 AddElement 메서드를 통해 새로운 요소를 추가할 수 있습니다.

main 함수에서는 두 개의 Page 객체를 생성한 뒤 Copy 객체에 추가하고, 복합체와 리프 각각에 대해 동일한 연산을 호출합니다. 실행 결과에서 확인할 수 있듯이, 클라이언트 코드는 복합 객체(myCopy)와 단일 객체(p1, p2)를 구분 없이 같은 방식으로 다룰 수 있습니다.

마무리

복합 패턴은 트리 형태의 계층 구조를 다루는 소프트웨어에서 코드의 일관성과 확장성을 크게 높여 줍니다. 파일 탐색기, 메뉴 시스템, UI 컴포넌트 트리 등 재귀적인 구조가 필요한 곳이라면 복합 패턴 적용을 적극적으로 고려해 볼 만합니다.