컴포지트(Composite) 패턴
15 May 2016 | 디자인패턴컴포지트(Composite) 패턴의 UML은 다음과 같습니다.
컴포지트 패턴의 개념은 각 객체들을 동일화시키겠다는 것입니다. 조금 다르게 표현하자면 추상적인 상위 클래스 하나를 만들고, 그 클래스를 상속받는 다양한 자식 클래스들을 만드는 것입니다. 그런 다음 그 자식 클래스들을 마치 같은 종류의 클래스 다루듯이 동일시해서 사용하겠다는 패턴입니다.
컴포지트 패턴은 커맨드(Command) 패턴이나 방문자(Visitor) 패턴, 데코레이터(Decorator) 패턴 등에 응용되서 사용되어질 수 있고, 상당히 널리 쓰이는 패턴입니다. 그리고 여기서 더 나아가 트리 구조와 같은 재귀적인(Recursive) 구조를 만들기 위해서도 유용하게 쓰이고 있습니다.
트리 구조의 가장 대표적인 예로는 ‘파일 구조’를 들 수 있습니다. 파일 구조는 폴더와 파일로 이루어져 있으며, 폴더 아래에는 폴더들이 있을 수 있고, 또한 파일들이 있을 수 있습니다.
예제 코드
컴포지트 패턴은 다음과 같이 Component, Leaf, Composite 로 구성됩니다.
public abstract class Component { // ... } public class Leaf extends Component { // ... } public class Composite extends Component { // ... private ArrayList list = new ArrayList(); public Component add(Component cp); public abstract void remove(Component cp); // ... }
위에서 언급했던 ‘파일 구조’ 예제를 들어보도록 하겠습니다.
Component
public abstract class Entry { public abstract String getName(); public abstract int getSize(); public void printList() { printList(""); } protected abstract void printList(String prefix); @Override public String toString() { return getName() + "(" + getSize() + ")"; } }
Leaf
public class File extends Entry { String name; int size; public File(String name, int size) { this.name = name; this.size = size; } @Override public String getName() { return this.name; } @Override public int getSize() { return this.size; } @Override protected void printList(String prefix) { System.out.println(prefix + "/" + this); } }
Composite
public class Directory extends Entry { String name; ArrayList<Entry> list = new ArrayList<>(); public Directory(String name) { this.name = name; } public void add(Entry item) { list.add(item); } public void remove(Entry item) { list.remove(item); } @Override public String getName() { return this.name; } @Override public int getSize() { int size = 0; for (Entry item: list) { size += item.getSize(); } return size; } @Override protected void printList(String prefix) { System.out.println(prefix + "/" + this); for (Entry item: list) { item.printList(prefix + "/" + name); } } }
Main
public class Main { public static void main(String[] args) { Directory root = new Directory("root"); Directory user = new Directory("user"); Directory snowdeer = new Directory("snowdeer"); Directory media = new Directory("media"); Directory image = new Directory("image"); Directory music = new Directory("music"); Directory video = new Directory("video"); root.add(user); root.add(media); user.add(snowdeer); media.add(image); media.add(music); media.add(video); snowdeer.add(new File(".bashrc", 42)); snowdeer.add(new File(".profile", 36)); image.add(new File("cat.png", 122)); image.add(new File("dog.png", 56)); image.add(new File("bird.png", 465)); music.add(new File("twice.png", 4382)); music.add(new File("apink.png", 7726)); video.add(new File("frozen.mp4", 341242)); root.printList(); } }