261. 컴포지트 (Composite) - 부분-전체 트리 구조 단일 객체 복합 객체 동일 취급 재귀적 구조 구조 패턴 GoF
핵심 인사이트: (모든 걸 퉁치는 공산주의 폴더 구조) 윈도우 파일 탐색기를 만들려는데,
[파일.txt]가 있고 그 파일을 담는[폴더]가 있다. 만약 멍청하게 코딩하면 "폴더 안에는 '파일 목록'과 '폴더 목록' 두 개를 따로 관리해야지!" 라고 짠다. 근데 내일 손자가 태어나서 폴더 안에 폴더 안에 폴더를 100번 중첩(트리)시키려면? 코드가 터진다! "야 ㅆㅂ!! 왜 '파일(단일 객체)'이랑 '폴더(복합 객체)'를 차별해!! 어차피 둘 다 아이콘이고 더블클릭하면 열리는 놈이잖아!! 당장 두 놈을[Node(노드)]라는 똑같은 껍데기(인터페이스)로 묶어서 하나로 퉁쳐버려!! 그럼 폴더(Node) 안에 파일(Node)을 넣든, 폴더 안에 또 폴더(Node)를 넣든, 시스템 입장에서는 그냥 똑같은 'Node' 덩어리들을 무한대로 집어넣는 거니까 무한 중첩 트리(Tree) 구조가 에러 없이 완벽하게 만들어지잖아!!" 부분(파일)과 전체(폴더)를 100% 동일한 놈으로 취급해 재귀적 지옥을 평정하는 구조 패턴, 컴포지트(Composite)다.
Ⅰ. 트리(Tree) 구조의 끔찍한 분기문 지옥
- 조직도를 그릴 때,
[부장]밑에[과장], 과장 밑에[대리], 대리 밑에[사원]이 있습니다. - 이 조직도의 연봉을 싹 다 합치려 합니다.
- 하수의 코드: "어, 부장이면 과장 리스트를 돌리고, 과장이면 대리 리스트를 돌리고..." 이렇게 뎁스(Depth)마다 클래스 타입을 확인하는
if-else분기문이 수십 개가 들어갑니다. (OCP 완전 위배)
Ⅱ. 컴포지트 (Composite) 패턴의 개념 🌟
- Composite (합성물, 혼합물)
- 개념: GoF 구조 패턴 중 하나로, 객체들을 나무뿌리처럼 뻗어 나가는 트리(Tree) 구조로 구성하여 '부분-전체' 계층을 표현하는 패턴입니다. 핵심은 사용자가 '단일 객체(Leaf 잎사귀)'와 이들을 모아둔 '복합 객체(Composite 나뭇가지)'를 구별하지 않고 완벽하게 동일한 껍데기(인터페이스)로 취급할 수 있게 해주는 마법입니다.
Ⅲ. 컴포지트의 3대 핵심 뼈대 🌟 핵심 🌟
- Component (추상적인 공통 껍데기):
- 윈도우 파일 탐색기의
[아이콘]또는[Node]라는 추상 클래스입니다. - 이 안에는
용량계산하기()같은 공통 함수 구멍이 파져 있습니다.
- 윈도우 파일 탐색기의
- Leaf (잎사귀 / 단일 객체):
- 자식이 없는 맨 밑바닥 부품입니다. (예:
[텍스트파일.txt]) 용량계산하기()를 부르면 쿨하게 "난 10MB야!"라고 자기 용량만 반환합니다.
- 자식이 없는 맨 밑바닥 부품입니다. (예:
- Composite (복합 객체 / 폴더) 🌟 (이게 핵심) 🌟:
- 1번 컴포넌트를 상속받은 놈이자, 자기 뱃속에 자식(Component)들을 List 배열로 무한정 품을 수 있는 '폴더' 객체입니다.
- 밖에서 폴더한테
용량계산하기()를 부르면? 자기가 직접 계산하지 않고, 자기 뱃속에 들어있는 모든 자식(파일이든 폴더든 상관없음)들에게 "야! 너네 용량 다 내놔!"라고 재귀적(Recursive)으로 함수를 넘겨버리고(위임) 그 합을 뭉쳐서 반환합니다.
Ⅳ. 왜 이게 마법인가? (클라이언트의 해방)
- 클라이언트(사용자)의 관점:
- "내가 찌른 놈이 가장 끄트머리
[텍스트 파일]인지, 아니면 수천 개의 파일이 든 거대한[C드라이브 폴더]인지 나는 1%도 알 필요가 없다!! 어차피 똑같은Component껍데기를 쓰고 있으니까 난 그냥용량계산하기()버튼만 한 번 누르면 끝난다!!" - 사용자는 1만 줄짜리 복잡한 트리 구조를, 단일 객체 다루듯 편안하게 조작할 수 있게 됩니다 (단순함의 극치).
- "내가 찌른 놈이 가장 끄트머리
📢 섹션 요약 비유: 컴포지트(Composite) 패턴은 거대한 '러시아 마트료시카 인형' 세트와 같습니다. 제일 큰 인형(폴더, 복합 객체)의 배를 가르면 중간 인형이 나오고, 중간 인형을 까면 작은 인형(폴더)이 또 나옵니다. 마지막으로 제일 작은 인형을 깠더니 인형이 아니라 '초콜릿 1개(파일, 단일 객체 Leaf)'가 나옵니다. 바보 같은 개발자(컴포지트 안 쓴 놈)는 인형과 초콜릿을 구별해서 따로따로 포장하는 뻘짓을 합니다. 하지만 컴포지트 패턴은 "야! 인형이든 초콜릿이든 어차피 내 배 속에 들어가는 '물건(Component)'이라는 본질은 똑같잖아!" 라며 둘을 완벽하게 동일한 껍데기 취급을 해버립니다. 이렇게 해두면 내가 "야 배 속에 있는 거 몸무게 다 합쳐봐!"라고 명령했을 때, 제일 큰 인형은 자기가 직접 무게를 재지 않고 자기 배 속의 중간 인형에게 똑같은 명령을 내리고, 중간 인형은 작은 인형에게 명령을 내리고, 마지막 초콜릿이 자기 무게를 뱉으면 그게 위로 스르륵 더해져서 한 방에 튀어나옵니다(재귀적 연산). 내가 쥐고 있는 게 초콜릿 1개인지, 초콜릿 1만 개가 든 거대 인형인지 전혀 알 필요 없이 똑같은 명령 한 번으로 거대한 트리 전체를 조종하게 해주는 가장 아름다운 구조 패턴입니다.