1. 컴포지트 패턴이란?
- 사용자가 단일 객체와 복합 객체 모두 동일하게 처리할 수 있음.
- 객체들의 관계를 트리구조로 구성하여 부분-전체 계층을 표현하고 각 구조들을 개별 객체들처럼 다룰 수 있는 구조패턴.
- 여러 객체의 합성(composite)을 제어할 수 있도록 하는 객체를 정의
- 동일한 타입의 자식 객체들을 관리하는 동일한 타입의 컴포지트 객체를 생성하여 관리하는 객체를 통해 자식 객체들에게 접근하는 패턴
- 복합 객체(Composite)와 단일 객체(Leaf)를 동일한 컴포넌트로 취급하여, 클라이언트에게 이 둘을 구분하지 않고 동일한 인터페이스를 사용하도록 하는 패턴.
2. 컴포지트 패턴을 사용하는 경우
- 전체-부분의 관계를 갖는 객체들 사이의 관계를 정의할 경우
- 여러 개체를 동일한 목적으로 사용하고 있으며, 각 개체들을 처리하는 코드가 거의 동일한 경우
- 데이터를 다룰 때 계층적인 트리 표현을 다루어야 하는 경우
- 복잡하고 난해한 단일/복합 객체의 관계를 단순화하고 싶은 경우
3. 컴포지트 패턴의 장점
1) 구조적 단점 해결 : 트리 계층 구조에서 상속이 가지는 문제를 해결해준다.
2) 일관성 : 다수의 단일 객체에 일일히 대응하지 않아도 복합 객체를 통해 간단하고 일관된 접근을 할 수 있음.
3) 가독성 : 새로운 단일 객체의 추가가 용이해지고, 이는 코드를 더 간략하게 하여 코드의 가독성을 높여준다.
4) 편의성 : 다형성 재귀를 통해 복잡한 트리구조를 보다 편리하게 구성할 수 있다.
4. 컴포지트 패턴의 단점
1) 깊이에 따른 제한 : 재귀 호출 특징 상 트리의 깊이(depth)가 깊어질수록 디버깅에 어려움이 생긴다.
2) 제약의 어려움 : 지나친 범용성으로 인해 새로운 요소를 추가할 때 복합 객체에서 구성 요소에 제약을 갖기 힘들다.
5. 코드 구현
using System;
using System.Collections.Generic;
namespace StudyCSharp
{
interface Component
{
void operation();
}
// 단일 객체
class Leaf : Component
{
string name;
public Leaf(string name)
{
this.name = name;
}
public void operation()
{
// 인터페이스 함수 구현
Console.WriteLine("호출\t" + name);
}
}
// 복합 객체
class Composite : Component
{
// Leaf와 Composite 객체 모두를 저장하여 관리하는 내부 리스트
List<Component> components = new List<Component>();
string name;
public Composite(string name)
{
this.name = name;
}
public void add(Component c)
{
components.Add(c); // 리스트 추가
}
public void remove(Component c)
{
components.Remove(c); // 리스트 삭제
}
public void operation()
{
// 인터페이스 함수 구현
Console.WriteLine("호출\t" + name);
// 내부 리스트를 순회하며, 단일 객체(Leaf)면 값을 출력,
// 복합 객체(Composite)면 다시 내부를 순회하는 재귀함수 호출
foreach(Component c in components)
{
c.operation(); // 자신의 함수를 재귀적으로 호출
}
}
public List<Component> getChild()
{
return components;
}
}
class Program
{
static void Main(string[] args)
{
// 1. 최상위 복합체 생성
Composite composite_1 = new Composite("composite_1");
// 2. 최상위 복합체에 저장할 Leaf와 또 다른 서브 복합체 생성
Leaf leaf_1 = new Leaf("leaf_1");
Composite composite_2 = new Composite("composite_2");
// 3. 최상위 복합체에 객체들을 등록
composite_1.add(leaf_1);
composite_1.add(composite_2);
// 4. 서브 복합체에 저장할 Leaf 생성
Leaf leaf_2 = new Leaf("leaf_2");
Leaf leaf_3 = new Leaf("leaf_3");
Leaf leaf_4 = new Leaf("leaf_4");
// 5. 서브 복합체에 개체들을 등록
composite_2.add(leaf_2);
composite_2.add(leaf_3);
composite_2.add(leaf_4);
// 6. 최상위 복합체의 모든 자식 노드들을 출력
composite_1.operation();
}
}
}
- 실행 결과
- 구조
<참고 사이트>