배경(Why)
전체-부분 구조를 갖는 경우, 트리로 이를 표현할 수 있다.
리프 노드와 브랜치를 구분해 개발을 진행하는 경우, if (leaf) else 이런식으로 구현하게 되면 복잡성이 높아지고 에러가 발생하기 쉬워진다!
How
이런 케이스는 어떻게 구현하는 게 좋을까?
Common Interface를 이용해 리프노드와 브랜치를 동일하게 취급하자!
즉,
- leaf => 자신 내에서만 연산
- composite => delegate all work to child components
이런 책임을 갖게 한다. 이렇게 구현하게 되면 클라이언트는 구체적인 클래스를 신경쓰지 않고 어떤 타입의 객체든 동일하게 다룰 수 있다. (OCR 만족)
What
위와 같이 동작하는 Composite Pattern이란,
객체들의 관계를 트리 구조로 구성하여 부분-전체 계층을 표현하는 패턴으로, 사용자가 단일 객체와 복합 객체 모두 동일하게 다루도록 하는 패턴이다.
- Component: Common Interface
- Leaf: 부분에 해당, Sub element가 없는 Basic element
- Composite: 전체에 해당, request를 하위트리로 전달함. 이 클래스 또한 Concrete sub element는 알지 못하고 Component를 통해 동작함!
언제 쓸까?(When)
- 트리와 비슷한 구조를 구현할 때
nested recursive object structure를 구현할 수 있다
- 클라이언트가 simple, complex element를 동일하게 다루기 원할 때(일관성)
shared interface가 있어서 클라이언트는 그 구체적인 타입을 몰라도 된다
Pros
- 복잡한 트리 구조를 쉽게 표현할 수 있다
- OCP를 만족해 new element type 추가에 자유롭다
Con
common interface를 뽑아내기가 어렵다. 오히려 overgeneralize 할 수 있다
vs. Decorator Pattern
두 패턴 다 recursive composition을 가져 비슷한 다이어그램으로 표현할 수 있다!
- Decorator: 한 chlid component만 가진다
👉 한 child component를 더해 책임을 더한다
- Composite: child components를 가진다
👉 just sum up
ref.
https://refactoring.guru/design-patterns/composite