복합체 패턴(Composite Pattern)은 전체 - 부분 관계를 가진 객체들을 트리 구조로 구성하여 한 개체로 다루는 방법을 제공합니다. 이 패턴은 개별 객체와 복합 객체를 동일하게 취급하여 클라이언트가 단일 객체와 복합 객체를 구별하지 않고 사용할 수 있도록 합니다. 이 패턴은 특히 계층적 구조를 가진 객체를 다루거나, 여러 객체를 하나의 객체로 처리해야 하는 상황에 유용하게 활용됩니다.
복합체 디자인 패턴 구조
- Component: 단일 객체(Leaf)와 복합 객체(Composite)가 구현하는 공통 인터페이스입니다. 이를 통해 클라이언트는 복합 객체와 단일 객체를 동일한 방식으로 다룹니다.
interface component {
void execute();
}
- Composite: 복합 객체로서, Leaf 역할이나 Composite 역할 넣어 관리하는 역할을 합니다. Leaf 객체와 다른 Composite 객체를 자식으로 가질 수 있습니다. 이를 통해 객체들은 트리 구조를 형성하게 됩니다.
class composite implements component {
private List<component> componentList;
@Overide
public void execute() {
System.out.print(this);
for(component c : componentList) {
c.execute();
}
}
public void add(Component component) {
componentList.add(component);
}
public void remove(Component component) {
componentList.remove(component)
}
public List<component> getChild() {
return componentList;
}
}
- Leaf: 단일 객체로서, 단순하게 내용물을 표시합니다. 이 객체들은 더 이상 하위 객체를 가지지 않으며, 구조의 끝을 위치합니다.
class Leaf implements component {
@Overide
public void execute() {
System.out.println(this);
}
}
복합체 패턴의 사용 예시
위에서 복합체 객체를 수도 코드를 간단하게 적어봤습니다.
과연 해당 패턴을 어디서 적합하게 사용될까요? 🤔🤔
대부분 협업에서 Spring 프레임워크에서 MVC패턴으로 구현하여 서버와 클라이언트 간에 데이터를 주고받을 겁니다. 여러 데이터 원본(DB, 외부 API, 등)에서 데이터를 가져와 합치거나 조작하는 경우 복합체 패턴을 사용하여 일관된 방식으로 처리할 수 있습니다. 특히 데이터의 계층 구조가 복잡하고 유연성이 필요한 경우에 복합체 패턴을 사용하면 코드의 유지보수성과 확장성을 향상할 수 있습니다.
사실 복합체 객체의 사용처를 찾아보면 대부분이 UI를 구성하는 요소들을 계층 구조로 구성하는 것으로 예시를 듭니다. 하지만 UI 구조를 만들 일이 없기에 다른 적합한 사용처를 꾸역꾸역 찾아서 아래와 같이 코드를 작성해 보았습니다. 😔
import java.util.ArrayList;
import java.util.List;
// Component interface
interface DataSource {
String fetchData();
}
// Leaf class representing a single data source
class SingleDataSource implements DataSource {
private String data;
public SingleDataSource(String data) {
this.data = data;
}
@Override
public String fetchData() {
return data;
}
}
// Composite class representing a collection of data sources
class CompositeDataSource implements DataSource {
private List<DataSource> dataSources;
public CompositeDataSource() {
dataSources = new ArrayList<>();
}
public void addDataSource(DataSource dataSource) {
dataSources.add(dataSource);
}
@Override
public String fetchData() {
StringBuilder result = new StringBuilder();
for (DataSource dataSource : dataSources) {
result.append(dataSource.fetchData()).append("\n");
}
return result.toString();
}
}
public class Main {
public static void main(String[] args) {
// Create individual data sources
DataSource dataSource1 = new SingleDataSource("Data from source 1");
DataSource dataSource2 = new SingleDataSource("Data from source 2");
// Create a composite data source
CompositeDataSource compositeDataSource = new CompositeDataSource();
compositeDataSource.addDataSource(dataSource1);
compositeDataSource.addDataSource(dataSource2);
// Fetch data from composite data source
System.out.println(compositeDataSource.fetchData());
}
}
위의 코드에서 'DataSource' 인터페이스는 Leaf와 Composite 클래스의 공통 인터페이스로 정의하였습니다. 'SingleDataSource' 클래스는 개별 데이터 소스를 나타내며, 'CompositeDataSource' 클래스는 여러 개의 데이터 소스를 담는 컨테이너 역할을 합니다. 이렇게 함으로 개별 데이터 소스와 복합 데이터 소스를 동일한 인터페이스를 통해 처리할 수 있습니다.
복합체 디자인패턴 장단점
장점
- 복합체 패턴은 구조적으로 복합 객체와 단일 객체를 동일한 인터페이스로 다룰 수 있도록 해 줍니다. 이는 클라이언트 코드가 구조의 복잡성을 알 필요 없이 일관된 방식으로 객체를 다룰 수 있게 해 줍니다.
- 새로운 구성 요소를 추가하거나 구조를 변경하는 것이 용이합니다. 이는 시스템이 변화에 대응하는 데 유리하며, 유지 보수가 쉽고 코드의 재상용성이 높아집니다.
- 계층 구조이기 때문에 복잡한 구조를 이해하고 관리하기 쉬워집니다.
단점
- 재귀 호출 특징 상 트리의 깊이가 깊어질수록 디버깅에 어려움이 생깁니다.
- 복합체 패턴을 적용할 때 모든 객체가 동일한 인터페이스를 구현하므로, 단일 책임 원칙(Single Responsibility Principle)을 위배할 가능성이 있습니다.
'Computer Science > Design Pattern' 카테고리의 다른 글
[Design Pattern] 빌더 패턴(Builder Pattern)에 대해서, @Builder - 컴도리돌이 (0) | 2024.05.05 |
---|---|
[Design Pattern] 퍼사드 패턴(Facade Pattern)에 대해서 - 컴도리돌이 (0) | 2024.04.04 |
[Design Pattern] 전략 패턴(Strategy Pattern)에 대해서 - 컴도리돌이 (2) | 2024.04.03 |
[Design Pattern] 데코레이터 패턴(Decorator Pattern)에 대해서 - 컴도리돌이 (0) | 2024.03.18 |
[Design Pattern] 추상 팩토리(Abstract Factory)에 대해서 - 컴도리돌이 (2) | 2024.01.24 |