On this page
article
Recursive Composition: Composite, Decortor
Composite Pattern
개념
여러 개의 객체를 하나의 큰 객체처럼 묶어서 처리할 수 있게 해주는 설계 패턴이다. 트리 구조를 이용해서 복잡한 계층을 만들 수 있고, 이 구조에서는 하나의 메뉴 항목(리프)이나 여러 개의 항목을 가진 메뉴(복합 객체)를 동일한 방식으로 다룰 수 있다.
예시
예를 들어 메뉴를 생각해보면 팝업 메뉴 안에 일반 메뉴 항목뿐만 아니라 또 다른 팝업 메뉴도 넣을 수 있다. 사용자는 이게 단일 항목인지 또 다른 메뉴 묶음인지 몰라도 되며, 그냥 command()
만 호출하면 알아서 잘 동작한다.
이 방식의 장점은, 메뉴가 하나든 여러 개든 똑같은 인터페이스(BaseMenu*)로 다룰 수 있다는 점이다. 코드 짜는 입장에서 신경 쓸 게 줄어들며 유지보수도 쉬워진다.
구조 클래스 설계
class BaseMenu {
public:
virtual void command() = 0;
virtual void add(BaseMenu* p) {}
virtual ~BaseMenu() {}
};
class MenuItem : public BaseMenu {
std::string name;
public:
MenuItem(const std::string& n) : name(n) {}
void command() override {
std::cout << name << " 메뉴 선택됨" << std::endl;
}
};
class PopupMenu : public BaseMenu {
std::string name;
std::vector<BaseMenu*> items;
public:
PopupMenu(const std::string& n) : name(n) {}
void add(BaseMenu* p) override {
items.push_back(p);
}
void command() override {
std::cout << "[ " << name << " ]" << std::endl;
for (size_t i = 0; i < items.size(); ++i) {
std::cout << i + 1 << ". ";
items[i]->command();
}
}
};
장점 요약
- 계층적 구조 표현이 쉬움
- 새로운 항목 추가가 쉬움 (객체 간 관계 설정만으로 확장)
- 클라이언트는
BaseMenu*
타입만 다루면 됨 (단일/복합 객체 구분 필요 없음)
Decorator Pattern
개념
객체에 동적으로 기능을 추가할 수 있는 설계 패턴이다. 상속이 아닌 포함을 이용하며, 중복 기능 확장에 유리하다.
특징
- 컴파일 시점이 아닌 런타임에 기능 추가
- 상속보다 조합 기반 설계를 지향
예시
struct IDraw {
virtual void draw() = 0;
virtual ~IDraw() {}
};
class Rectangle : public IDraw {
public:
void draw() override {
std::cout << "Rectangle" << std::endl;
}
};
class ColorDecorator : public IDraw {
IDraw* inner;
public:
ColorDecorator(IDraw* d) : inner(d) {}
void draw() override {
std::cout << "[Color] ";
inner->draw();
}
};
class ShadowDecorator : public IDraw {
IDraw* inner;
public:
ShadowDecorator(IDraw* d) : inner(d) {}
void draw() override {
std::cout << "[Shadow] ";
inner->draw();
}
};
int main() {
IDraw* rect = new Rectangle;
IDraw* colored = new ColorDecorator(rect);
IDraw* shadowed = new ShadowDecorator(colored);
shadowed->draw();
delete shadowed; // 내부도 소멸 필요 시 smart pointer 권장
}
실제 사례
C#의 Stream 체인 구성 예:
FileStream → CryptoStream → ZipStream → Write()
비교 요약
패턴 | 특징 | 사용 목적 |
---|---|---|
Composite | 트리 구조, 복합 객체 구성 | 구조를 계층적으로 표현 |
Decorator | 런타임 기능 확장, 중첩 가능 | 기능을 유연하게 조합 |
이처럼 두 패턴은 구조(Composite)와 기능(Decorator) 측면에서 각각 객체지향의 유연성을 극대화하는 방식이다.