10월 17일 - Composite Pattern

Yullgiii·2024년 10월 17일
0

Composite Pattern

목적

Composite Pattern의 목적은 객체의 계층 구조를 표현하고 각 객체를 동일한 인터페이스로 독립적으로 처리할 수 있도록 하는 것이다. 이를 통해 클라이언트는 개별 객체(Leaf)와 객체 그룹(Composite)을 같은 방식으로 다룰 수 있다.

Class Diagram과 설명

Composite Pattern의 기본 구성은 Component, Leaf, 그리고 Composite 클래스로 이루어진다. 아래 그림은 Composite Pattern의 클래스 다이어그램을 나타낸다.

Component 클래스

ComponentLeafComposite 클래스에서 공통적으로 사용되는 메서드를 선언한 추상 클래스 또는 인터페이스다. 여기서 메서드들은 기본적으로 예외를 발생시키도록 구현되어, Leaf가 사용하지 않는 메서드 호출 시 예외가 발생하게 된다.

public abstract class Component {
    public void operation() {
        throw new UnsupportedOperationException();
    }
    
    public void add(Component component) {
        throw new UnsupportedOperationException();
    }
    
    public void remove(Component component) {
        throw new UnsupportedOperationException();
    }
    
    public Component getChild(int i) {
        throw new UnsupportedOperationException();
    }
}

Leaf 클래스

Leaf 클래스는 트리의 말단 요소를 의미하며, 개별 객체를 나타낸다. Component 클래스에서 필요한 메서드만 구현하며, 다른 메서드를 호출할 경우 UnsupportedOperationException이 발생하게 된다.

public class Leaf extends Component {
    private String name;
    
    public Leaf(String name) {
        this.name = name;
    }
    
    @Override
    public void operation() {
        System.out.println("Leaf " + name + " operation 수행");
    }
}

Composite 클래스

Composite 클래스는 여러 Component 객체를 포함할 수 있으며, 이 객체들을 재귀적으로 처리하는 역할을 한다. add, remove, getChild 메서드를 구현하여 자식 컴포넌트를 관리할 수 있다.

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

public class Composite extends Component {
    private ArrayList<Component> components = new ArrayList<>();
    private String name;
    
    public Composite(String name) {
        this.name = name;
    }
    
    @Override
    public void operation() {
        System.out.println("Composite " + name + " operation 수행");
        for (Component component : components) {
            component.operation();
        }
    }
    
    public void add(Component component) {
        components.add(component);
    }

    public void remove(Component component) {
        components.remove(component);
    }

    public Component getChild(int i) {
        return components.get(i);
    }
}

구현 시 고려사항

  1. 부모만 자식을 참조할 것인가, 자식도 부모를 참조해야 할 것인가?
    구조를 구현하기 전에 자식이 부모를 참조해야 하는지 고려하는 것이 중요하다.

  2. 어떤 클래스가 자식을 관리할 것인가?
    일반적으로 Composite 클래스가 자식을 관리하지만, 관리 함수가 Component 클래스에 있는 경우 장단점을 고려해야 한다.

Composite Pattern의 두 가지 구현 방법

1.Transparency 방식
Component 클래스에 add, remove, getChild 같은 자식 관리 메서드를 선언하여, Leaf와 Composite 클래스를 구분하지 않고 동일한 Component로 다룰 수 있게 한다.

  • 장점: Leaf와 Composite 클래스를 구분할 필요가 없다.
  • 단점: Leaf 클래스가 자식 관리 메서드를 호출할 경우 런타임에 예외가 발생한다.
  1. Safety 방식
    자식 관리 메서드를 Composite 클래스에만 선언하여 자식 관리 기능이 필요한 경우에만 해당 메서드를 사용할 수 있도록 한다.
  • 장점: Leaf 클래스가 자식 관리 메서드를 호출할 경우 컴파일 타임에 오류를 확인할 수 있다.
  • 단점: Leaf와 Composite 클래스를 구분해야 한다.

관련 패턴

Decorator

  • 공통점: 두 패턴 모두 재귀적으로 객체를 구성한다.
  • 차이점: Decorator 패턴은 객체에 책임을 추가하는 데 중점을 두지만, Composite 패턴은 계층 구조를 표현하는 데 주로 사용된다.

Iterator

  • 공통점: 두 패턴 모두 aggregate 객체를 순차적으로 접근할 수 있게 한다.
  • 차이점: Composite 패턴은 계층 구조를 표현하기 위한 것이며, Iterator는 순차적 접근이 핵심 기능이다.

So...

Composite Pattern은 객체의 계층 구조를 동일한 인터페이스로 관리할 수 있게 하여 클라이언트 코드의 복잡성을 줄인다. Composite와 Leaf 객체를 구분하지 않고, 공통된 인터페이스를 통해 처리하는 점에서 구조의 일관성을 유지할 수 있는 장점이 있다. 이러한 구조 덕분에 클라이언트는 복잡한 계층 구조를 신경 쓰지 않고 단순히 Component로 다룰 수 있어, 관리와 확장성을 확보할 수 있다.

profile
개발이란 무엇인가..를 공부하는 거북이의 성장일기 🐢

0개의 댓글