Design Pattern

[Design Pattern] 컴포지트 패턴

0so0 2023. 8. 16. 19:00
728x90
반응형
SMALL

컴포지트(Composite)패턴에 대한 정리

 

컴포지트(Composite)

객체를 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만든 것
클라이언트에서 개별 객체와 다른 객체들로 구성된 복합 객체를 똑같은 방법으로 다룰 수 있음

 

사용 이유

  • 부분-전체 관계를 가진 객체가 있고, 그 객체들을 모두 같은 방식으로 다루고 싶을때 사용
  • 객체의 구조가 복잡할 때 객체 간의 결합도를 낮추어 유연성을 높이기 위해 사용

* 부분-전체 관계 : gui에서 프레임, 패널같은 최상위 구성요소가 있고 그 안에 메뉴나 텍스트들, 버튼, 스크롤 등이 있는것

구조

 

  • 복합 객체 : 복합객체, 잎으로 분류되고 아래와 같은 트리구조를 이룸

사용 예시

  • MenuComponent  : 메뉴 아이템과, 메뉴 모두에 적용되는 공용 인터페이스 역할을 하는 구성요소 인터페이스
class MenuComponent {
    MenuComponent( const MenuComponent& ); // Disable copy constructor
    void operator=( const MenuComponent& ); // Disable assignment operator
public:
    MenuComponent();
    virtual ~MenuComponent();
    virtual void add( MenuComponent* menuComponent );
    virtual void remove( MenuComponent* menuComponent );
    virtual string getName() const;
    virtual string getDescription() const;
    virtual double getPrice() const;
    virtual bool isVegetarian() const;
    virtual void print() const;
}
  • MenuItem  : MenuComponent 를 상속받고, 메뉴 아이템에  쓰일법한 메소드만 오버라이드
class MenuItem : public MenuComponent {

    string _name;
    string _description;
    bool _vegetarian;
    double _price;
public:
    MenuItem( const string name, const string description, bool vegetarian, double price );
    string getName() const;
    string getDescription() const;
    double getPrice() const;
    bool isVegetarian() const;
    void print() const;
};

MenuItem::MenuItem( const string name, const string description, bool vegetarian, double price ) :
                    _name( name ), _description( description ), _vegetarian( vegetarian ), _price( price )
{
    PrintMessage("MenuItem::MenuItem");
}

string MenuItem::getName() const
{
    PrintMessage("MenuItem::getName");
    return _name;
}

string MenuItem::getDescription() const
{
    PrintMessage("MenuItem::getDescription");
    return _description;
}

double MenuItem::getPrice() const
{
    PrintMessage("MenuItem::getPrice");
    return _price;
}

bool MenuItem::isVegetarian() const
{
    PrintMessage("MenuItem::isVegetarian");
    return _vegetarian;
}
  • Menu : MenuComponent 를 상속받고, 메뉴에서 쓰일법한 메소드만 오버라이드
class Menu : public MenuComponent {

    string _name;
    string _description;
    mutable vector<MenuComponent*> _menuComponents;

public:
    Menu( const string name, const string description );
    void add( MenuComponent* menuComponent );
    void remove( MenuComponent* menuComponent );
    string getName() const;
    string getDescription() const;
    void print() const;
};

Menu::Menu( const string name, const string description ) :_name( name ), _description( description )
{
    PrintMessage("Menu::Menu");
}
void Menu::add( MenuComponent* menuComponent )
{
    assert( menuComponent );
    PrintMessage("Menu::add");
    _menuComponents.push_back( menuComponent );
}
string Menu::getName() const
{
    PrintMessage("Menu::getName");
    return _name;
}

string Menu::getDescription() const
{
    PrintMessage("Menu::getDescription");
    return _description;
}
  • 메뉴 추가 : 메뉴 객체를 만들고, 복합 객체의 add 메소드를 사용하여 최상위 메뉴인 allMenus에 각 메뉴 추가
unique_ptr< MenuComponent > pancakeHouseMenu(new Menu( "PANCAKE HOUSE MENU", "Breakfast" ) );
unique_ptr< MenuComponent > cafeMenu(new Menu( "CAFE MENU", "Dinner" ) );
unique_ptr< MenuComponent > dinerMenu(new Menu( "DINER MENU", "Lunch" ) );
unique_ptr< MenuComponent > allMenus(new Menu( "ALL MENUS", "All menus combined" ) );

allMenus->add( pancakeHouseMenu.get() );
allMenus->add( cafeMenu.get() );
allMenus->add( dinerMenu.get() );

  • 메뉴 아이템 추가
pancakeHouseMenu->add( new MenuItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99) );
pancakeHouseMenu->add( new MenuItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99) );
pancakeHouseMenu->add( new MenuItem("Blueberry Pancakes", "Pancakes made with fresh blueberries, and blueberry syrup", true, 3.49) );

  • 메뉴, 메뉴 아이템 추가
unique_ptr< MenuComponent > dessertMenu(new Menu( "DESSERT MENU", "Dessert of course!" ) );
dinerMenu->add( dessertMenu.get() );
dessertMenu->add( new MenuItem("Apple Pie", "Apple pie with a flakey crust, topped with vanilla icecream", true, 1.59) );
dessertMenu->add( new MenuItem("Cheesecake", "Creamy New York cheesecake, with a chocolate graham crust", true, 1.99) );

 

정리

  • 한 클래스에서는 한 역할만 맡아야하는 단일 역할 원칙에 위배되지만, 투명성 확보
  • 안정성이 떨어짐 -> 위 예시에서 메뉴 아이템에 메뉴를 넣는 작업을 할 수도 있음
  • 클라이언트를 단순화시켜 사용하기 편리함
728x90
반응형
LIST

'Design Pattern' 카테고리의 다른 글

[Design Pattern] MVVM 패턴  (0) 2023.10.03
[Design Pattern] 싱글톤 패턴  (0) 2023.08.01
[Design Pattern] 디자인 패턴 종류  (0) 2023.07.03