본문 바로가기

: Desgin Pattern

Composite Pattern

반응형

 

 

Composite Pattern Objectives

객체의 생성을 표현해주는 구조 패턴(Structural Pattern)이다. Scope는 Object이다.
객체들 간 계층 구조를 만들어주고, 여러 오브젝트를 구분하지 않고 동일한 인터페이스를 통해서 처리할 수 있도록 하는 것이다.

 

 

Problems

트리가 있는 구조를 예시로 보자.

 

menu example

위와 같은 많은 메뉴들이 주어질 질 때, 어떻게 하면 이 메뉴들을 처리할 수 있을까?

if ... else if 로 모두 나누어 처리하면 되지 않을까라는 생각을 할 수도 있다. 하지만, composite pattern 을사용해서 통합적으로 관리할 수 있다. 우선 클래스 다이어 그램으로 어떻게 표현되는지 알아보자

 

 

Composite Pattern Class Diagram

Component는 추상 클래스이며, operation() 함수를 갖고 있으며,
Composite 를 object로 갖고 있다. (composition and delegation) 

Leaf와 Composite는 Component를 상속 받는 형태이다. Leaf는 말그대로 단말노드이다. Composite는 iterator 패턴과 함께 자주 사용되며, Component를 제어하기 위한 권한을 위임 받아 처리한다.

코드로 쓰면 아래와 같다.

public abstract class Component {
    
    public abstract void operation();
}

public class Composite extends Component {
    Component[] components;

    public void add(Component component);
    public void remove(Component component);
    public void getChind(Component component);
    void operation();
}

public class Leaf extends Component {

    public void operation();
}

 

Waitress 가 메뉴를 안내하는 경우를 상상해보도록 하자.

Client는 Waiteress, Component는 MenuComponent , Leaf 는 MenuItem, Composite는 Menu 로 하자.
 참고로 Client는 Component를 통해 접근하는 사용자이다.

여기서 Component 는 MenuComponent 라는 새로운 객체를 생성하고, Leaf는 MenuItem, Composite은 Menu로 구성한다.
이렇게 구성하게되면 Client는 MenuComponent만 알면, 모든 operation 을 수행할 수 있다.

위의 메뉴 예제에서 모든 메뉴에 대해서 출력을 하고 싶은 경우를 가정하자.

// Client
public class Waitress {
    MenuComponent allMenus;
    
    public Waitress(MenuComponent allMenus) {
        this.allMenus = allMenus;
    }
    
    public void printMenu() { 
        allMenus.print();
    }
}

// Component
public class MenuComponent {

    public void print();
    public void add(MenuComponent compnent);
    public void remove(MenuComponent compnent);
    public void getChild(int i);
}

// Composite
public class Menu extends MenuComponent {

    ArrayList<MenuComponent> menuComponents = new ArrayList<>();
    String name;
    String description;

    public Menu(String name, String description);

    public void print();
    public void add(MenuComponent compnent);
    public void remove(MenuComponent compnent);
    public void getChild(int i);
}

// Leaf
public class MenuItem extends MenuComponent {
    
    String name;
    String description;    

    public MenuItem(String name, String description);

    public void print();
}

Menu 클래스는 menuComponents 를 Collections 형태로 갖고 있으며, 모든 동작 함수들을 갖고 있다.

MenuComponent menu = new Menu("All Menu", "Welcome to the restaurant");
menu.add("Brunch", "For morning");
menu.add("Coffee", "Kenya AA");

Waitress waitress = new Waitress(menu);
waitress.printMenu();

MenuComponent 객체를 통해 메뉴를 생성하고, 메뉴에 아이템을 등록한 다음 waitress 객체를 통해 메뉴를 출력할 수 있다.

 

Transparency vs Safety (Composite Pattern)

Transparent vs safe

Transperncy를 선택할 경우, 모든 오브젝트는 Component에서 필요한 걸 다 호출하게 할 수 있다. 그러나, 자식노드에서 add(), remove(), getChind() 같은 함수는 불릴 수가 없다. 이러한 경우에 예외처리를 다 해주어야한다.

반대로, Safety를 선택한 경우, Leaf에 필요없는 함수들이 추가되어 있지 않으므로, 에러나는 경우의 수를 줄일 수 있다. (==안전하다). 하지만 leaf와 composite가 다른 interface를 가지므로 훨씬 더 까다롭다.

 

Related Patterns

Decorator 와 구조가 유사하다.

Iterator를 자주 사용한다.

반응형

': Desgin Pattern' 카테고리의 다른 글

MVC  (0) 2021.08.19
Adapter Pattern  (0) 2021.07.25
Design Pattern  (0) 2021.07.05