Design Pattern

Design Pattern 09 - Composite Pattern(복합체 패턴)

gloomyfox 2019. 6. 26. 01:13

의도

부분과 전체의 계층을 표현하기 위해 객체들을 모아 트리 구조로 구성합니다. 사용자로 하여금 개별 객체와 복합 객체를 동일하게 다룰 수 있도록 하는 패턴입니다.

 

 

동기

구조도 캡처 시스템 혹은 파워 포인트 도형 편집기와 같은 그래픽 응용 프로그램을 살펴보면, 사용자가 간단한 그림 구성 요소들을 모아서 복잡한 다이어그램을 생성할 수 있습니다. 사용자는 더 큰 그림 요소를 만들기 위해 구성 요소들을 그룹으로 만들고 이 그룹이 더 큰 그룹을 형성하기도 합니다. 이를 구현하기 위한 간단한 방법은 텍스트, 라인 등 간단한 기본 그림 요소에 대한 클래스들을 정의하고, 이를 포함한 컨테이너로 동작하는 클래스를 추가로 정의하는 것 입니다.

 

그러나 이 접근법에는 문제가 있습니다. 각 그림에 해당하는 클래스들과 컨테이너 클래스들을 구분하기 위해 클래스의 속성으로 크기, 색, 위치 등의 기본 속성 이외에 코드에 해당하는 속성을 정의해야 합니다. 또 이를 사용하는 어플리케이션에서는 코드 값을 기억하고 코드에 따라서 여러 분기를 처리해야 합니다. 즉, 처리 대상이 컨테이너에 해당하는지, 개별 그림 요소에 해당하는지 판단하고 적절한 처리가 되도록 구현해야 하는 문제가 있습니다.

 

이를 위한 Composite 패턴의 가장 중요한 요소는 기본 클래스와 이들의 컨테이너를 모두 표현할 수 있는 하나의 추상화 클래스를 정의하는 것 입니다. 어플리케이션은 단일체이던 복합체(그룹)이던 Composite 패턴의 Component 클래스에 정의된 연산으로만 접근하는 일관성을 가질 수 있습니다.

 

구조

 

 

참여자

- Component: 집합 관계에 정의될 모든 객체에 대한 인터페이스를 정의합니다. 모든 클래스에 해당하는 인터페이스에 대해서는 공통의 행동을 구현합니다. 전체 클래스에 속한 요소들을 관리하는 데 필요한 인터페이스를 정의합니다. 순환 구조에서 요소들을 관리하는 데 필요한 인터페이스를 정의합니다. 순환 구조에서 요소들을 포함하는 전체 클래스로 접근하는데 필요한 인터페이스를 정의하며, 적절하다면 그 인터페이스를 구현합니다.

- Leaf: 가장 말단의 객체, 즉 자식이 없는 객체를 나타냅니다. 객체 합성에 가장 기본이 되는 객체의 행동을 정의합니다.

- Composite: 자식이 있는 구성 요소에 대한 행동을 정의합니다. 자신이 복합하는 요소들을 저장하면서, Component 인터페이스에 정의된 자식 관련 연산을 구현합니다.

- Client: Component 인터페이스를 통해 복합 구조 내의 객체들을 조작합니다.

 

 

결과

장점

- 기본 객체와 복합 객체로 구성된 하나의 일관된 클래스 계통을 정의합니다. 런타임 기본 객체와 복합 객체를 구분하지 않고 일관되게 프로그래밍 가능합니다.

- 사용자 코드가 단순해집니다. 복합 구조나 단일 객체나 동일한 코드로 작성되기 때문입니다.

- 새로운 종류의 구성 요소를 쉽게 추가할 수 있습니다. 새롭게 정의된 Composite나 Leaf의 서브클래스들은 기존에 존재하는 구조들과 독립적으로 동작이 가능하게 됩니다.

 

단점

- 설계가 지나치게 범용성을 많이 가집니다. 복합체의 구성 요소에 제약을 가하기 힘듭니다. 복합체가 오직 한 개의 구성 요소만 있었으면 할 때가 있는데 Composite 클래스만 가지고는 이를 제어하기 어렵기에 런타임 점검이 들어가게 됩니다.

 

 

구현

/** "Component" */
interface Graphic {

    //Prints the graphic.
    public void print();

}

/** "Composite" */
class CompositeGraphic implements Graphic {

    //Collection of child graphics.
    private List<Graphic> mChildGraphics = new ArrayList<Graphic>();

    //Prints the graphic.
    public void print() {
        for (Graphic graphic : mChildGraphics) {
            graphic.print();
        }
    }

    //Adds the graphic to the composition.
    public void add(Graphic graphic) {
        mChildGraphics.add(graphic);
    }

    //Removes the graphic from the composition.
    public void remove(Graphic graphic) {
        mChildGraphics.remove(graphic);
    }

}


/** "Leaf" */
class Ellipse implements Graphic {

    //Prints the graphic.
    public void print() {
        System.out.println("Ellipse");
    }

}


/** Client */
public class Program {

    public static void main(String[] args) {
        //Initialize four ellipses
        Ellipse ellipse1 = new Ellipse();
        Ellipse ellipse2 = new Ellipse();
        Ellipse ellipse3 = new Ellipse();
        Ellipse ellipse4 = new Ellipse();

        //Initialize three composite graphics
        CompositeGraphic graphic = new CompositeGraphic();
        CompositeGraphic graphic1 = new CompositeGraphic();
        CompositeGraphic graphic2 = new CompositeGraphic();

        //Composes the graphics
        graphic1.add(ellipse1);
        graphic1.add(ellipse2);
        graphic1.add(ellipse3);

        graphic2.add(ellipse4);

        graphic.add(graphic1);
        graphic.add(graphic2);

        //Prints the complete graphic (four times the string "Ellipse").
        graphic.print();
    }
}