cs/디자인 패턴
[디자인 패턴]Composite Pattern
sang_hoony
2019. 1. 20. 00:44
Composite Pattern
Composite Pattern은 단일 객체와 복합객체를 동일하게 처리하기 편하게 만들어줍니다.
그리고 동일한 객체를 반복해서 처리하는 과정에서 재귀적인 구조를 만드는데 도움을 주는 패턴입니다.
이번 예제코드에서는 폴더와 파일 디렉토리 구조를 만드는 예제를 만들어 보겠습니다.
파일과, 폴더를 함께말해서 Entry라고 말하겠습니다.
Entry.java
public abstract class Entry{
public abstract String getName();
public abstract int getSize();
public void printLine(){
printLine("");
}
public abstract void printLine(String prefix);
public abstract Entry add(Entry entry);
public String toString(){
return "/"+getName()+" ("+getSize()+")";
}
}
하위 클래스에서 구현하고 있습니다.
File.java(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 name;
}
@Override
public int getSize() {
return size;
}
@Override
public void printLine(String prefix) {
System.out.println(prefix+"/"+this);
}
@Override
public Entry add(Entry entry) {
return null;
}
}
나는 잘 몰랐는데 Entry class에서 toString을 오버라이딩 해주고있다. printLine에서 문자열과 덧셈 연산에서 this를 불러주면 자동으로 toString()이 호출된 다는 것이다.
this.toString()
toString()
this
모두 동일한 결과가 나온다.
Directory(Composite)
import java.util.ArrayList;
import java.util.Iterator;
public class Directory extends Entry{
private String name;
private int size = 0;
private ArrayList documents = new ArrayList();
public Directory(String name){
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public int getSize() {
Iterator iterator = documents.iterator();
while(iterator.hasNext()){
Entry entry = (Entry)iterator.next();
size+=entry.getSize();
}
return size;
}
@Override
public void printLine(String prefix) {
System.out.println(prefix+"/"+this);
Iterator iterator = documents.iterator();
while(iterator.hasNext()){
Entry entry = (Entry) iterator.next();
entry.printLine(prefix+"/"+entry.getName());
}
}
@Override
public Entry add(Entry entry) {
documents.add(entry);
return this;
}
}
Directory에서는 File객체가 오든 Doucments객체가 오든 size메소드에서나 printLine에서나 동일하게 처리하는 것을 볼 수 있다.
Main
public class Main {
public static void main(String[] args){
try{
Directory rootdir = makeDirectory("root");
Directory bindir = makeDirectory("bin");
Directory tmpdir = makeDirectory("tmp");
Directory usrdir = makeDirectory("usr");
rootdir.add(bindir);
rootdir.add(tmpdir);
rootdir.add(usrdir);
bindir.add(makeFile("vi", 10000));
bindir.add(makeFile("latex", 20000));
rootdir.printLine();
}catch (FileTreatmentException e){
e.printStackTrace();
}
}
public static Directory makeDirectory(String name){
return new Directory(name);
}
public static File makeFile(String name, int size){
return new File(name, size);
}
}
Entry.py
import abc
class Entry:
__metaclass__ = abc.ABCMeta
def get_name(self):
pass
def get_size(self):
pass
def print_line(self):
self.print_path("")
def print_path(self, prefix):
pass
def __repr__(self):
return self.get_name() + " (" + str(self.get_size()) + ")\n"
python에서는 오버로딩이 안된다.
File.py
from Entry import Entry
class File(Entry):
def __init__(self, name, size):
self.size = size
self.name = name
def print_path(self, prefix):
print(prefix+"/"+super().__repr__())
def get_name(self):
return self.name
def get_size(self):
return self.size
java에서는 toString을 호출하기 위해 this를 넘겨주면 됐지만 여기서는 __repr__()을 넘겨주었다. 사실 java와 같은 방법으로 python으로 어떻게 사용해야하는지 모르겠다.
from Entry import Entry
class Directory(Entry):
def __init__(self, name):
self.name = name
self.array = []
def print_path(self, prefix):
print(prefix+"/"+super().__repr__())
for fileDirec in self.array:
fileDirec.print_path(prefix+"/"+self.name)
def add(self, entry):
self.array.append(entry)
def get_name(self):
return self.name
def get_size(self):
size = 0
for fileDirec in self.array:
size += fileDirec.get_size()
return size
기본적인 로직은 java와 같다. array에 등록된 것을 호출해주며 자동적으로 재귀가 실행된다.
main.py
from Directory import Directory
from File import File
if __name__ == "__main__":
root = Directory("root")
bin = Directory("bin")
tmp = Directory("tmp")
usr = Directory("usr")
root.add(bin)
root.add(tmp)
root.add(usr)
bin.add(File("vi", 10000))
bin.add(File("latex", 20000))
root.print_line()
결과