본문 바로가기
Delvelopment/DesignPattern

[Design Pattern] 복합체 패턴, 컴포지트 패턴 (Composite Pattern)

by 제제킴 2022. 7. 9.
반응형

컴포지트 패턴(Composite Pattern) 으로 객체를 트리구조로 구성해서 부분-전체 계층구조를 구현합니다. 컴포지트 패턴을 사용하면 클라이언트에서 개별 객체와 복합 객체를 똑같은 방법으로 다룰 수 있습니다.

이 패턴을 사용하면 중첩되어 있는 그룹과 항목을 똑같은 구조 내에서 처리 할 수 있습니다. 그룹과 항목을 같은 구조에 넣어서 부분 - 전체 계층 구조(part-whole hierarchy)를 생성할 수 있습니다.

여기서 부분 - 전체 계층 구조란, 부분들이 계층을 이루고 있지만 모든 부분을 묶어서 전체로 다룰 수 있는 구조를 말합니다.

  • 컴포지트 패턴을 사용하면 객체의 구성과 개별 객체를 노드로 가지는 트리 형태의 객체 구조를 만들 수 있습니다.
  • 이런 복합 구조(composite structure)를 사용하면 복합 객체와 개별 객체를 대상으로 똑같은 작업을 적용할 수 있습니다.
  • 즉, 복합 객체와 개별 객체를 구분할 필요가 거의 없어집니다.

해드퍼스트 디자인패턴

 

package pattern.composite;

public abstract class MenuComponent {

    public void add(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public void remove(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public MenuComponent getChild(int i) {
        throw new UnsupportedOperationException();
    }

    public String getName() {
        throw new UnsupportedOperationException();
    }

    public String getDescription() {
        throw new UnsupportedOperationException();
    }

    public double getPrice() {
        throw new UnsupportedOperationException();
    }

    public boolean isVegetarian() {
        throw new UnsupportedOperationException();
    }

    public void print() {
        throw new UnsupportedOperationException();
    }

}
package pattern.composite;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Menu extends MenuComponent {
    List<MenuComponent> menuComponents = new ArrayList<MenuComponent>();
    String name;
    String description;

    public Menu(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public void add(MenuComponent menuComponent) {
        menuComponents.add(menuComponent);
    }

    public void remove(MenuComponent menuComponent) {
        menuComponents.remove(menuComponent);
    }

    public MenuComponent getChild(int i) {
        return menuComponents.get(i);
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public void print() {
        System.out.print("\\n" + getName());
        System.out.println(", " + getDescription());
        System.out.println("---------------------");

        Iterator<MenuComponent> iterator = menuComponents.iterator();
        while (iterator.hasNext()) {
            MenuComponent menuComponent = iterator.next();
            menuComponent.print();
        }
    }
}
package pattern.composite;

public class MenuItem extends MenuComponent {
    String name;
    String description;
    boolean vegetarian;
    double price;

    public MenuItem(String name, String description, boolean vegetarian, double price) {
        this.name = name;
        this.description = description;
        this.vegetarian = vegetarian;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public double getPrice() {
        return price;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public void print() {
        System.out.print("  " + getName());
        if (isVegetarian()) {
            System.out.print("(v)");
        }
        System.out.println(", " + getPrice());
        System.out.println("     -- " + getDescription());
    }
}
package pattern.composite;

public class Waitress {
    MenuComponent allMenus;

    public Waitress(MenuComponent allMenus) {
        this.allMenus = allMenus;
    }

    public void printMenu() {
        allMenus.print();
    }
}
package pattern.composite;

public class MenuTestDrive {

    public MenuTestDrive() {
        MenuComponent pancakeHouseMenu =
                new Menu("팬케이크 하우스 메뉴", "아침메뉴");
        MenuComponent dinerMenu =
                new Menu("객체마을 식당 메뉴", "점심 메뉴");
        MenuComponent cafeMenu =
                new Menu("카페 메뉴", "저녁 메뉴 ");
        MenuComponent dessertMenu =
                new Menu("디저트 메뉴", "디저트를 즐겨 보세요!");
//        MenuComponent coffeeMenu = new Menu("커피 메뉴", "Stuff to go with your afternoon coffee");

        MenuComponent allMenus = new Menu("전체 메뉴", "전체 메뉴");

        allMenus.add(pancakeHouseMenu);
        allMenus.add(dinerMenu);
        allMenus.add(cafeMenu);

        pancakeHouseMenu.add(new MenuItem(
                "K&B 팬케이크 세트",
                "스크램블 에그",
                true,
                2.99));
        pancakeHouseMenu.add(new MenuItem(
                "레귤러 팬케이크 세트",
                "달걀",
                false,
                2.99));
        pancakeHouseMenu.add(new MenuItem(
                "블루베리 팬케이크",
                "신선한 블루베리",
                true,
                3.49));
        pancakeHouseMenu.add(new MenuItem(
                "와플",
                "취향에 따라 .. 와플",
                true,
                3.5));

        dinerMenu.add(new MenuItem(
                "채식주의자용 BLT",
                "통밀 위에 콩고기 베이컨...",
                true,
                2.99));
        dinerMenu.add(new MenuItem(
                "BLT",
                "통 밀위에 베이컨 ..",
                false,
                2.99));
        dinerMenu.add(new MenuItem(
                "오늘의 스프",
                "감자 샐러드로...",
                false,
                3.29));
        dinerMenu.add(new MenuItem(
                "핫도그",
                "핫도그..임",
                false,
                3.05));
        dinerMenu.add(new MenuItem(
                "찐 채소와 브라운 라이스",
                "찐 채소와 라이스...",
                true,
                3.99));

        dinerMenu.add(new MenuItem(
                "파스타",
                "마리나라 소스 스파게티 ...",
                true,
                3.89));

        dinerMenu.add(dessertMenu);

        dessertMenu.add(new MenuItem(
                "애플 파이",
                "애플 파이..",
                true,
                1.59));

        dessertMenu.add(new MenuItem(
                "치즈케이크",
                "뉴욕 치즈케이크",
                true,
                1.99));
        dessertMenu.add(new MenuItem(
                "소르베",
                "라스베리와 라임의 절묘한 조화",
                true,
                1.89));

        cafeMenu.add(new MenuItem(
                "배지 버거와 에어 프라이",
                "배지 버거와 에어 프라이...",
                true,
                3.99));
        cafeMenu.add(new MenuItem(
                "오늘의 스프",
                "오늘의 스프",
                false,
                3.69));
        cafeMenu.add(new MenuItem(
                "브리토",
                "콩과 살사, 부리토",
                true,
                4.29));
        

        Waitress waitress = new Waitress(allMenus);

        waitress.printMenu();
    }
}
  • 컴포지트 패턴에서는 단일 역할 원칙을 깨는 대신 투명성을 확보하는 패턴이라고 할 수 있다.
  • 투명성(transparency)란 Component 인터페이스에 자식들을 관리하는 기능과 잎으로써의 기능을 전부 넣어서 클라이어늩가 복합 객체와 잎을 똑같은 방식으로 처리할 수 있도록 만들 수 있다.
  • 상황에 따라 원칙을 적절하게 사용해야 함을 보여 주는 대표 사례라고 볼 수 있다.
반응형

댓글