콤포지트 패턴이란?

 

Composite = 복합체

복합체 패턴이라고도 부름

 

1) 어려운 설명

사용자가 단일객체와 복합객체를 모두 동일하게 다룰 수 있도록 객체들의 관계를 트리구조로 구성해서 부분-전체 계층을 표현하는 패턴

 

2) 쉬운 설명

예를들어 root 폴더는 여러 파일과 하위 폴더를 포함하고 있음.

또한 하위 폴더도 여러 파일과 폴더를 포함하고 있음.

 

만약 해당 객체의 이름을 출력하고 싶다면

파일 객체라면 파일 이름 하나만 출력하면 되므로 showFileName()함수를 사용하면 끝이겠지만

폴더객체의 경우 폴더이름과 하위 파일과 하위 폴더까지 출력해야 하므로 파일 한개만 출력하는 showFileName()함수와는 다른 기능이 필요하므로 showFolderName()함수를 따로 구현해야 함

하지만 사용자 입장에서 파일이건 폴더건 그냥 showName()함수로 사용 가능하게 만드는게 콤포지트 패턴

 

즉 개별객체이건, 복합객체이건 동일한 인터페이스로 사용하게 만들고자 조상클래스로 추상클래스를 만들어서 트리구조로 구조화하는 패턴

 

 

 

콤포지트 패턴의 구조

 

부분과 전체의 계층을 표현하기 위해 객체들을 하나의 인터페이스(Component)로 묶어 트리구조로 구조화

위의 예시로 설명하자면 Leaf는 파일, Composite(복합체)는 폴더가 되며

파일객체이건 폴더객체이건 상관없이 하나의 인터페이스로 사용 가능하게 만드는 구조

Composite 패턴의 두가지 조건

1) 개별객체와 복합객체가 공통의 조상클래스(위에서는 Component)를 가져야 함

2) 개별객체와 복합객체는 사용하는 방법이 동일해야 함, 또한 동일한 동작을 수행하는 함수(위에서는 operation함수)는 조상클래스에 위치해야 함

 

 

 

구현 코드 예시

 

1) Component 클래스

집합관계에 정의될 모든 객체에 대한 인터페이스를 정의하는 곳

Leaf와 Composite클래스를 트리화하기 위한 추상클래스

class Component {
protected:
    string componentName;
    
public:
    Component(string componentName) {
        this->componentName = componentName;
    }
    virtual ~Component(){ }
    
    virtual void ShowName() const = 0; //operation
};

 

2) Leaf 클래스

가장 말단의 역할을 하는 클래스

class File : public Component {
public:
    File(string fileName) 
    	: Component(fileName)
    { }
    
    virtual void ShowName() const {
        cout << this->componentName << endl;
    }
};

 

3) Composite 클래스

여러개의 Leaf와 Composite를 관리하는 클래스이며 각 객체를 vector에 보관하는 식으로 구현

class Folder : public Component {
private:
    vector<Component*> children;

public:
    Folder(string folderName)
        : Component(folderName)
    { }

    virtual void ShowName() const {
        cout << this->componentName << " child list" << endl;

        for (vector<Component*>::const_iterator it = children.begin(); it != children.end(); ++it) {
            (*it)->ShowName();
        }
    }

    void addFile(Component* component) {
        children.push_back(component);
    }

};

 

4) main함수

/root

    └ config.txt

    └ /usr

          └ guest1

          └ guest2

위의 폴더구조를 만든 뒤 ShowName()함수 사용

int main(int argc, const char * argv[]) {
    Folder* root = new Folder("root");
    root->addFile(new File("config.txt"));
    
    Folder* usr =new Folder("usr");
    root->addFile(usr);
    usr->addFile(new File("guest1"));
    usr->addFile(new File("guest2"));    
    
    root->ShowName();
    return 0;
}

 

5) 실행결과

 

 

 

 

 

 

※ 참고 문헌

https://devji.tistory.com/entry/C-%EC%BB%B4%ED%8F%AC%EC%A7%93-%ED%8C%A8%ED%84%B4-Composite-pattern

https://d-yong.tistory.com/38

https://devjino.tistory.com/27

https://ko.wikipedia.org/wiki/%EC%BB%B4%ED%8F%AC%EC%A7%80%ED%8A%B8_%ED%8C%A8%ED%84%B4