복합체 패턴

ynkim·2024년 12월 26일
0

복합체

객체들을 트리 구조로 구성한 후 개별 객체들처럼 작업할 수 있도록 하는 구조 패턴이다. 객체 트리의 모든 컴포넌트들에 대해 재귀적으로 행동을 실행할 수 있다.

구조

  • 컴포넌트: 인터페이스로 선언하여 트리의 공통적인 작업을 설명
  • 잎: 트리의 기본 요소로 하위 요소가 없고 실제 작업을 수행
  • 컨테이너(복합체): 하위 요소들이 있는 요소. 자녀들의 구상 클래스를 알지 못하고 컴포넌트 인터페이스를 통해서만 하위 요소들과 작동. 컨테이너는 요청을 받았을 때 작업을 하위 요소들에 위임하고 중간 결과를 처리한 뒤 최종 결과를 클라이언트에게 반환
  • 클라이언트: 컴포넌트 인터페이스를 통해 모든 요소들과 작동

예시 코드

// Component 인터페이스
interface Graphic {
    void move(int x, int y);
    void draw();
}

// Leaf 클래스
class Dot implements Graphic {
    private int x, y;

    public Dot(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public void move(int x, int y) {
        this.x += x;
        this.y += y;
    }

    @Override
    public void draw() {
        System.out.println("Drawing a dot at (" + x + ", " + y + ")");
    }
}

// Leaf를 확장한 Circle 클래스
class Circle extends Dot {
    private int radius;

    public Circle(int x, int y, int radius) {
        super(x, y);
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Drawing a circle at (" + x + ", " + y + ") with radius " + radius);
    }
}

// Composite 클래스
class CompoundGraphic implements Graphic {
    private final List<Graphic> children = new ArrayList<>();

    public void add(Graphic child) {
        children.add(child);
    }

    public void remove(Graphic child) {
        children.remove(child);
    }

    @Override
    public void move(int x, int y) {
        for (Graphic child : children) {
            child.move(x, y);
        }
    }

    @Override
    public void draw() {
        System.out.println("Drawing a compound graphic:");
        for (Graphic child : children) {
            child.draw();
        }
    }
}

// Client 클래스
class ImageEditor {
    private CompoundGraphic all;

    public void load() {
        all = new CompoundGraphic();
        all.add(new Dot(1, 2));
        all.add(new Circle(5, 3, 10));
    }

    public void groupSelected(List<Graphic> components) {
        CompoundGraphic group = new CompoundGraphic();
        for (Graphic component : components) {
            group.add(component);
            all.remove(component);
        }
        all.add(group);
        all.draw();
    }

    public void drawAll() {
        all.draw();
    }
}

public class Main {
    public static void main(String[] args) {
        ImageEditor editor = new ImageEditor();
        editor.load();

        List<Graphic> selectedComponents = new ArrayList<>();
        selectedComponents.add(new Dot(10, 20));
        selectedComponents.add(new Circle(15, 25, 5));

        editor.groupSelected(selectedComponents);
        editor.drawAll();
    }
}
  1. 트리 구조로 표현할 수 있는지 확인하고 단순 요소와 컨테이너로 분해한다.
  2. 공통 메서드들을 포함하는 컴포넌트 인터페이스를 선언한다.
  3. 단순 요소를 나타내는 리프 클래스를 생성한다. 여러 개가 있을 수 있다.
  4. 복잡한 요소를 나타내는 컨테이너 클래스를 만드는데 이 클래스는 인터페이스 유형으로 된 리스트를 가진다.
  5. 컨테이너에 자식 요소를 추가/제거하는 메서드를 정의한다.

장단점

장점

  • 복잡한 트리구조를 편리하게 작업할 수 있다.
  • 개방/폐쇄 원칙: 객체 트리와 작동하는 기존 코드를 훼손하지 않고 새로운 요소 유형들을 도입할 수 있다.
    단점
  • 기능이 너무 다른 클래스들에는 공통 인터페이스를 제공하기 어려울 수 있다.
  • 컴포넌트 인터페이스를 과하게 일반화하게 되면 이해하기 어렵다.

0개의 댓글