개별 객체(잎, Leaf)와 객체들의 묶음(가지, Composite)을 같은 인터페이스로 다뤄, 트리 구조를 재귀적으로 처리하는 패턴.
interface FsNode { size(): number }
class FileNode implements FsNode {
constructor(private bytes: number) {}
size() { return this.bytes }
}
class FolderNode implements FsNode {
constructor(private children: FsNode[]) {}
size() { return this.children.reduce((sum, c) => sum + c.size(), 0) }
}- 호출자는 파일인지 폴더인지 신경 쓰지 않고
size()만 부른다. 트리 순회 로직이 각 노드 안에 들어간다(재귀, 트리 순회) - 파일 시스템, 조직도, UI 컴포넌트 트리, 문서의 중첩 구조처럼 부분-전체 관계에 잘 맞는다
- 모든 노드에 같은 인터페이스를 강제하다 보면 잎에 의미 없는
addChild()같은 메서드가 생긴다. 공통 연산만 인터페이스에 두고 자식 관리는 가지에만 둔다
React의 컴포넌트 트리 자체가 이 구조다. 컴포넌트가 다른 컴포넌트를 children으로 품고, 어느 깊이에서든 같은 방식으로 렌더링된다(React 엘리먼트와 JSX). 이를 API 설계로 끌어올린 것이 컴파운드 컴포넌트다. 구조 패턴 전체는 구조 패턴.