Lee's Grow up

[디자인패턴/Design Pattern] Composite Pattern / 컴포지트 패턴 본문

PROGRAMMING/디자인패턴

[디자인패턴/Design Pattern] Composite Pattern / 컴포지트 패턴

효기로그 2019. 12. 17. 15:06
반응형

관련 내용은 [자바 언어로 배우는 디자인 패턴 입문],[Head First Design Pattern]의 내용을 참고해서 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 부탁드립니다.

1. Composite 패턴이란?


개별 객체와 복합 객체를 똑같은 방법으로 취급하는 것, 해당 패턴을 사용하면 객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층 구조로 만들 수 있습니다.

2. Composite 패턴의 등장인물


  • Leaf(나뭇잎)의 역할
    1. '단일객체'을 표시하는 역할을 수행하며, 내부에는 다른 것을 넣을 수 없습니다.
  • Composite(복합체)의 역할
    1. '복합객체'를 나타내는 역할을 하며, Leaf나 Composite 역할을 넣을 수 있습니다.
  • Component의 역할
    1. Leaf, Composite의 역할을 동일시하는 역할이며, 둘의 상위 클래스입니다.
Composite 패턴의 클래스 다이어그램

3. 예제


3-1. MenuComponent 클래스

우선 Component역할인 MenuComponent 클래스입니다.

public abstract class MenuComponent {

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

    // 기타 필요한 메소드 정의

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

디자인의 원칙에 의해서 인터페이스로 선언하지 않고 추상 클래스로 선언한 이유는
Leaf, Composite는 역할이 달라서 각 역할에 맞는 기본 메소드를 구현하기 불가능 하기 때문에 예외처리 라는 기본 구현을 제공하기 위해서 추상 클래스를 사용하였습니다.

3-2. MenuItem 클래스

Leaf 역할입니다.

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

    // 생성자, 게터 생략

    public void print() {
        System.out.println(" - " + getName() + " : " + getPrice());
        System.out.println("    -- " + getDescription());
    }
}

단일 객체로써 필요한 동작을 하면 역할은 끝입니다.

3-3. Menu 클래스

Composite 역할입니다.

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

    // 생성자, 게터 생략

    public void print() {
        System.out.println(getName() + ", " + getDescription());
        System.out.println("-----------------------------------------");
        Iterator iterator = menuComponents.iterator();
        while(iterator.hasNext()) {
            MenuComponent menuComponent = 
                    (MenuComponent) iterator.next();
            menuComponent.print();
        }
        System.out.println();
    }
}

Composite 요소는 Compoent 요소를 자식으로 가집니다. 그래서 자식들을 관리하기 위한 print() 메소드를 재정의 합니다.

3-4. Main 클래스
public class Main {
    public static void main(String[] args) {
        MenuComponent pancakeHouseMenu = new Menu ("팬케이크 하우스 메뉴", "런치 메뉴");

        MenuComponent cafeMenu = new Menu ("카페메뉴", "브런치 메뉴");

        MenuComponent dessertMenu = new Menu ("디저트 메뉴", "디저트를 즐겨 보세요!");

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

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

        pancakeHouseMenu.add(new MenuItem("기본 팬케이크", "고소한 기본 팬 케이크", 4400));
        pancakeHouseMenu.add(new MenuItem("블루베리 팬케이크", "달콤한 블루베리 시럽이 추가된 팬 케이크", 6400));

        // 기타 메뉴 추가 생략

        allMenus.print();
    }
}

전체 트리의 맨 위구조를 가질 allEmnusComposite역할을 하는 { pancakeHouseMenu, cafeMenu, dessertMenu }를 담아주고 각각의 집합체에 Leaf역을 하는 MenuItem을 추가해줍니다.

실행 결과
전체 메뉴,  전체 메뉴
-----------------------------------------
팬케이크 하우스 메뉴, 런치 메뉴
-----------------------------------------
 - 기본 팬케이크 : 4400.0
    -- 고소한 기본 팬 케이크
 - 블루베리 팬케이크 : 6400.0
    -- 달콤한 블루베리 시럽이 추가된 팬 케이크

카페메뉴, 브런치 메뉴
-----------------------------------------
 - 치즈 케이크 : 23000.0
    -- 이달의 인기 치즈 케이크입니다.
 - 초코 쿠키 : 2000.0
    -- 바삭한 초코 쿠키입니다.

디저트 메뉴, 디저트를 즐겨 보세요!
-----------------------------------------
 - 팥빙수 : 4500.0
    -- 여름철 더위를 책임질 오리지널 팥빙수입니다.
 - 우유 : 1500.0
    -- 고소한 소화가 잘되는 우유입니다.


전체 트리 구조의 간략한 모양입니다.

3-5. 왜 사용할까?
  • 위 트리구조 예시에서 처럼 복합 객체와 단일 객체의 처리 방법이 다르지 않을 경우, 전체 - 부분 관계로 정의할 수 있다.
    트리 구조로 표현하고 싶은 경우 사용

4. 관련 패턴


  • Command 패턴 : '매크로 커맨드'를 만들 때 Composite 패턴이 사용됩니다.
  • Visitor 패턴 : Composite를 순환하면서 처리하는데 사용합니다.
  • Decorator 패턴 : 장식과 내용물을 동일시합니다. 동일시 한다는 공통점이 있습니다. link
반응형
Comments