의도 : 부분과 전체의 계층을 표현하기 위해 객체들을 모아 트리 구조로 구성함 개별 객체와 복합 객체를 모두 동일하게 다룰 수 있도록 하는 패턴
부분 - 전체의 객체 계통을 표현하고 싶거나 사용자가 객체의 합성으로 생긴 복합 객체와 개별 객체 사이의 차이를 알지 않고도 자기 일을 할 수 있도록 만들고 싶을 때 사용함 사용자는 복합 구조의 모든 객체를 똑같이 취급하게 됨
구조 :
참여자 :
협력 방법 : 사용자는 복합 구조 내 객체 간의 상호작용을 위해 Component 클래스 인터페이스를 사용하며 요청받은 대상이 Leaf 인스턴스이면 자신이 정의한 행동을 직접 수행하고 대상이 Composite이면 자식 객체들에게 요청을 위임함
예제 :
public abstract class Component {
private String name;
public Component(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Folder extends Component{
List<Component> children = new LinkedList<>();
public Folder(String name) {
super(name);
}
public List<Component> getChildren() {
return children;
}
public void addComponent(Component component) {
children.add(component);
}
public void removeComponent(Component component) {
children.remove(component);
}
}
public class File extends Component {
private Object data;
public File(String name) {
super(name);
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
public class Main {
public static void main(String[] args) {
Folder
root = new Folder("root"),
download = new Folder("download"),
document = new Folder("document"),
picture = new Folder("picture"),
music = new Folder("music");
File
down1 = new File("down1"),
down2 = new File("down2"),
pic1 = new File("pic1"),
pic2 = new File("pic2"),
music1 = new File("music1"),
music2 = new File("music2");
root.addComponent(download);
root.addComponent(document);
document.addComponent(picture);
document.addComponent(music);
download.addComponent(down1);
download.addComponent(down2);
picture.addComponent(pic1);
picture.addComponent(pic2);
music.addComponent(music1);
music.addComponent(music2);
show(root);
}
private static void show(Component component) {
System.out.println(component.getClass().getName() + "|" + component.getName());
if (component instanceof Folder) {
for (Component c : ((Folder)component).getChildren()) {
show(c);
}
}
}
}
투명성 : 자식을 관리하는 인터페이스를 최상위에 위치 시킬 경우 서브클래스 모두에게 동일한 인터페이스가 적용되므로 투명성을 보장함 하지만 사용자가 Leaf 클래스의 인스턴스에 Add()나 Remove() 연산을 호출하는 불필요한 경우가 없도록 하는 데에 비용 소모
안전성 : Composite 클래스에서 자식을 관리하는 연산을 정의하면 Leaf 클래스에서는 이러한 연산을 호출할 수 없으므로 안전성을 보장 받지만 Leaf 클래스와 Composite 클래스가 다른 인터페이스를 갖게 되므로 사용자는 이를 동일한 대상으로 간주하고 사용할 수 없음
Case :
사용예 : Smalltalk의 모델/뷰/컨트롤러에서 View 클래스는 서브뷰 집합을 포함하고 있어 Component 클래스이자 Composite 클래스이기도 함