반응형
복합체 패턴이란?
컴포지트 패턴 혹은 복합체 패턴이라고 불리는 이 패턴은 객체들을 트리구조로 구성하여 개별객체와 복합 객체를 동일하게 취급할 수 있도록 하는 구조적 디자인패턴이다.
이를 통해서 단일객체와 복합객체를 일관된 방식으로 다룰 수 있게 된다.
왜 사용해야 하는가?
- 단일 객체와 복합 객체를 동일하게 취급하기 때문에 클라이언트 쪽에서 코드를 일관된 방식으로 사용할 수 있게 된다.
- 재귀적인 구조로 편리하게 구현할 수 있다.
- 새로운 단일 객체나 복합 객체를 추가할 때 기존의 코드를 수정하지 않는다.
어떤 경우에 사용해야 하는가?
- 나무처럼 계층적인 부분-전체 구조를 갖고 있을 때 사용하면 좋다.
예를 들어, 그래픽 요소나, 문서 구조등이 있다. - 클라이언트가 일관된 인터페이스로 사용해야 할 때 사용하면 좋다.
데코레이터 패턴 모두 객체를 감싸는 데 사용한다.
하지만 데코레이터 패턴은 기능을 추가하거나 수정하는데 중점을 두지만,
복합체는 부분과 전체를 일관된 방식으로 처리하는 데 중점을 둔다.
문제점
- 재귀를 사용하기 때문에 객체가 많이 중첩된 경우 성능이 떨어질 수 있다.
- 단일 객체와 복합객체를 동일한 인터페이스로 추상화해야 하기 때문에 설계가 어려워질 수 있다.
구현 방법
간단한 파일 시스템을 만들어 보자
여러 종류가 있지만 이중 Ordinary Files와 Directories를 가지고 와 간단하게 구현해 보자!
해당 구조를 토대로 직접 만들어보도록 한다.
먼저 File 인터페이스를 만들어서 이름과 사이즈를 구하는 메서드로 추상화를 진행하였다.
package com.example.designpattern.composite.file;
public interface File {
int getSize();
String getName();
}
해당 인터페이스들을 implements 일반 파일과 폴더를 구현해 주자!
먼저 다른 File을 담을 수 있는 복합객체인 Directory를 만들어주자.
package com.example.designpattern.composite.file;
import java.util.ArrayList;
import java.util.List;
public class Directory implements File{
private List<File> files;
private String name;
public Directory(String name) {
this.name = name;
files = new ArrayList<>();
}
public void addFile(File file) {
this.files.add(file);
}
public List<File> getFiles() {
return this.files;
}
@Override
public int getSize() {
int sumSize = 0;
for (File file : files) {
sumSize += file.getSize();
}
return sumSize;
}
@Override
public String getName() {
return this.name;
}
}
중요한 점은 getSize에 재귀적 특징을 이용해서 list에 들어있는 모든 하위 객체들의 size를 더해주는 것이다.
노드의 leaf에 해당하는 개별 객체인 Ordinary File 또한 구현해 주자.
package com.example.designpattern.composite.file;
public class OrdinaryFile implements File {
private String name;
private int size;
public OrdinaryFile(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public int getSize() {
return this.size;
}
@Override
public String getName() {
return this.name;
}
}
특별할 것 없는 일반적인 객체로 계층의 leaf node에 해당한다.
package com.example.designpattern.composite;
import com.example.designpattern.composite.file.Directory;
import com.example.designpattern.composite.file.File;
import com.example.designpattern.composite.file.OrdinaryFile;
public class Main {
public static void main(String[] args) {
// 메인 복합객체 생성하기
Directory rootDirectory = new Directory("루트디렉터리");
// 메인복합객체에 단일객체 넣기
OrdinaryFile internet = new OrdinaryFile("인터넷", 50);
OrdinaryFile notePad = new OrdinaryFile("메모장", 5);
rootDirectory.addFile(internet);
rootDirectory.addFile(notePad);
// 복합객체 안에 복합객체 넣기
Directory gameDirectory = new Directory("게임디렉터리");
OrdinaryFile lostArk = new OrdinaryFile("잃어버린 방주", 2550);
OrdinaryFile lol = new OrdinaryFile("전설들의 경기", 1200);
gameDirectory.addFile(lostArk);
gameDirectory.addFile(lol);
rootDirectory.addFile(gameDirectory);
// 정보 출력하기
// 복합객체 확인
printSize(rootDirectory);
printSize(gameDirectory);
// 단일 객체 확인
printSize(lostArk);
}
private static void printSize(File file) {
int sumSize = file.getSize();
System.out.println(file.getName() + "의 용량은 " + sumSize + "입니다.");
}
}
해당 클래스를 사용하는 클라이언트의 입장에선 복합객체나 개별객체들을 동일하게 사용할 수 있는 모습을 확인할 수 있다.
루트디렉터리의 용량은 3805입니다.
게임디렉터리의 용량은 3750입니다.
잃어버린 방주의 용량은 2550입니다.
반응형
'Design Pattern > 구조 패턴(Structural patterns)' 카테고리의 다른 글
Flyweight Pattern, 플라이웨이트 패턴 (0) | 2024.02.14 |
---|---|
Facade Pattern, 퍼사드 패턴 (0) | 2024.02.07 |
Decorator Pattern, 데코레이터 패턴 (1) | 2024.02.06 |
Bridge Pattern, 브릿지 패턴 (0) | 2024.02.05 |
Adapter Pattern, 어댑터 패턴 (0) | 2024.02.01 |