소프트웨어 마에스트로 과정에서 멘토님, 팀원들과 디자인패턴 세미나를 진행하고 있습니다. 이번에는 Composite 패턴에 대해 설명드리겠습니다.
💡 Java언어로 배우는 디자인 패턴 입문 책을 참고하여 포스팅하였습니다.
컴퓨터의 파일 시스템에는 디렉터리 라는 것이 있습니다. 디렉터리 안에는 파일이 있거나 하위 디렉터리가 있기도 합니다. 또 그 하위 디렉터리 안에는 다른 파일이나 하위 디렉터리가 있을 수 있습니다. 이처럼 디렉터리는 재귀적인 구조를 만듭니다.
디렉터리와 파일은 서로 다르지만 모두 디렉터리 안에 넣을 수 있는 것입니다. 따라서 디렉터리와 파일을 합해서 디렉터리 엔드리라는 이름으로 부르며 둘을 같은 종류로 간주하기도 합니다.
이번에 배울 Composite 패턴은 디렉터리와 파일을 동일시하여 재귀적인 구조를 만들기 위한 디자인 패턴입니다.
아래 표는 클래스 종류를 나타냅니다
이름 | 해설 |
---|---|
Entry | File과 Directory를 동일시하는 추상 클래스 |
File | 파일을 나타내는 클래스 |
Directory | 디렉터리를 나타내는 클래스 |
FileTreatmentException | 파일에 Entry를 추가하려고 할 때 발생하는 예외 클래스 |
Main | 동작 테스트용 클래스 |
예제 프로그램의 클래스 다이어그램
package composite;
public abstract class Entry {
public abstract String getName();
public abstract int getSize();
public Entry add(Entry entry) throws FileTreatmentException{
throw new FileTreatmentException();
}
public void printList() {
printList("");
}
protected abstract void printList(String prefix);
public String toString() {
return getName() + " ("+getSize()+")";
}
}
package composite;
public class File extends Entry {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
public String getName() {
return name;
}
public int getSize() {
return size;
}
@Override
protected void printList(String prefix) {
System.out.println(prefix + "/" + this);
}
}
package composite;
import java.util.ArrayList;
public class Directory extends Entry {
private String name;
private ArrayList directory = new ArrayList();
public Directory(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
public int getSize() {
int size = 0;
for (Object o : directory) {
Entry entry = (Entry) o;
size += entry.getSize();
}
return size;
}
@Override
public Entry add(Entry entry) {
directory.add(entry);
return this;
}
@Override
protected void printList(String prefix) {
System.out.println(prefix + "/" + this);
for (Object o : directory) {
Entry entry = (Entry) o;
entry.printList(prefix + "/" + name);
}
}
}
package composite;
public class FileTreatmentException extends RuntimeException {
public FileTreatmentException() {
}
public FileTreatmentException(String message) {
super(message);
}
}
import composite.Directory;
import composite.File;
import composite.FileTreatmentException;
public class Main {
public static void main(String[] args) {
try{
System.out.println("Making root entries...");
Directory rootdir = new Directory("root");
Directory bindir = new Directory("bin");
Directory tmpdir = new Directory("tmp");
Directory usrdir = new Directory("usr");
rootdir.add(bindir);
rootdir.add(tmpdir);
rootdir.add(usrdir);
bindir.add(new File("vi", 10000));
bindir.add(new File("latex", 20000));
rootdir.printList();
System.out.println("");
System.out.println("Making user entries");
Directory kim = new Directory("Kim");
Directory Lee = new Directory("Lee");
Directory park = new Directory("Park");
usrdir.add(kim);
usrdir.add(Lee);
usrdir.add(park);
kim.add(new File("diary.html", 100));
kim.add(new File("Comosite.java", 200));
Lee.add(new File("memo.text", 300));
park.add(new File("game.doc", 400));
park.add(new File("junk.mail", 500));
rootdir.printList();
}catch(FileTreatmentException e){
e.printStackTrace();
}
}
}