오늘은 디자인 패턴 스터디 두번째 항목인 컴포지트 패턴에 대해 알아보도록 하겠습니다.
컴포지트 패턴(Composite Pattern)
객체 지향 디자인 패턴 중 하나로, 복합 객체를 구성하는 개별적인 객체들을 모두 동일한 방법으로 다룰 수 있게 하는 패턴입니다.
이 패턴은 개별 객체와 복합 객체(그룹화된 객체)를 동일하게 다룰 수 있도록 하여 클라이언트 코드가 객체 계층 구조를 일관되게 처리할 수 있도록 도와줍니다.
컴포지트 패턴은 트리 구조를 가진 객체들을 다루는데 유용합니다.
간단한 예시로, 파일 시스템을 생각해볼 수 있습니다.
파일 시스템에서 디렉터리와 파일을 구성하는 것과 같이, 여러개의 객체가 포함된 복합 객체를 처리할 때 이용할 수 있습니다.
이러한 패턴을 사용하는 이유는,
코드가 많으면, 코드의 복잡도가 상승하고, 그에따라 에러가 발생할 확률이 높아집니다.
컴포지트 패턴을 사용하게되면, 개별 객체와 복합 객체를 동일한 인터페이스로 다룰 수 있는데,
개별 객체는 단순히 자기 자신을 다루는 방법으로 처리되고,
복합객체는 자신에게 속한 개별 객체를 재귀적으로 다룰 수 있습니다.
이렇게하면, 클라이언트는 개별 객체와 복합 객체를 구분하지 않고 동일한 방식으로 사용할 수 있다는 장점을 가집니다.
파일과 디렉터리는 각각 단일 객체와 복합 객체에 해당합니다. 파일과 디렉터리 모두 공통된 인터페이스를 가지며,
디렉터리 안에는 또 다른 파일이나 디렉터리를 포함할 수 있습니다.
이러한 패턴의 장점 중 하나는 클라이언트 코드가 객체의 구체적인 타입을 몰라도 되며,
일관된 방식으로 상호작용할 수 있다는 것입니다.
객체의 계층 구조가 변경되어도 클라이언트 코드에는 영향을 주지 않고 사용이 가능하므로 유연성이 향상됩니다.
import java.util.ArrayList;
import java.util.List;
// Component 인터페이스
interface Component {
void display();
}
/*
Component는 Leaf 객체와 Composite 객체가 공통적으로 가져야 하는 메서드를 정의하는 인터페이스입니다.
*/
// Leaf 객체: File 클래스
class File implements Component {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void display() {
System.out.println("File: " + name);
}
}
/*
File 클래스는 Leaf 객체로, 파일을 나타냅니다.
파일의 이름을 저장하고, display 메서드를 구현하여 파일 정보를 출력합니다.
*/
// Composite 객체: Directory 클래스
class Directory implements Component {
private String name;
private List<Component> components = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
public void addComponent(Component component) {
components.add(component);
}
@Override
public void display() {
System.out.println("Directory: " + name);
for (Component component : components) {
component.display();
}
}
}
/*
Directory 클래스는 Composite 객체로, 디렉터리를 나타냅니다.
디렉터리의 이름을 저장하고, 하위에 속한 컴포넌트들을 저장하는 List<Component> components를 가지고 있습니다.
addComponent 메서드를 통해 컴포넌트(파일 또는 디렉터리)를 추가할 수 있습니다.
display 메서드는 현재 디렉터리 정보를 출력하고, 속한 각 컴포넌트의 display 메서드를 호출하여 하위 구조를 출력합니다.
*/
// 클라이언트 코드
public class CompositePatternExample {
public static void main(String[] args) {
// 파일 생성
File file1 = new File("File 1");
File file2 = new File("File 2");
// 디렉터리 생성
Directory dir1 = new Directory("Directory 1");
Directory dir2 = new Directory("Directory 2");
// 디렉터리에 파일 추가
dir1.addComponent(file1);
dir2.addComponent(file2);
// 또 다른 디렉터리 생성
Directory dir3 = new Directory("Directory 3");
// 두 번째 디렉터리에 첫 번째 디렉터리와 또 다른 디렉터리 추가
dir2.addComponent(dir1);
dir2.addComponent(dir3);
// 전체 구조 출력
dir2.display();
}
}
/*
main 메서드에서는 간단한 파일 시스템을 생성하고 출력하는 예시를 보여줍니다.
File 객체 두 개와 Directory 객체 세 개를 생성하여 조합합니다.
마지막으로 두 번째 디렉터리의 display 메서드를 호출하여 전체 파일 시스템 구조를 출력합니다.
*/
코드 실행결과
Directory: Directory 2
File: File 2
Directory: Directory 1
File: File 1
Directory: Directory 3
컴포지트 패턴은 개별 객체와 복합 객체 처리 방법이 같을 때,
전체 - 부분 관계로 정의할 수 있습니다.
객체의 구조가 복잡할 때 유용하며,
객체 간의 결합도를 낮추어 유연성을 높일 수 있고,
새로운 개별 객체나 복합 객체를 추가하더라도 클라이언트 코드를 수정할 필요가 없어 유지보수에 좋습니다.
참고문헌
https://jangjjolkit.tistory.com/60
'Design Pattern' 카테고리의 다른 글
Design Pattern | 브리지 패턴(Bridge Pattern) (0) | 2024.08.29 |
---|---|
Design Pattern | 빌더 패턴(Builder Pattern) (2) | 2024.04.26 |
Design Pattern | 전략 패턴(Strategy Pattern) (0) | 2024.04.01 |
Design Pattern | 데코레이터 패턴(Decorator Pattern) (1) | 2024.03.22 |
Design Pattern | 추상 팩토리 패턴(Abstract Factory Pattern) (0) | 2024.01.30 |