디자인패턴 - 컴포지트 패턴(Composite Pattern)

2019. 8. 19. 14:07프로그래밍언어/디자인패턴

composite의 의미는 '합성의', '합성물', '혼합 양식'이다. 이를 통해 composite 패턴이 뭔가 합쳐진 형태임을 짐작할 수 있다. 또 composite 패턴의 구성을 보면 일반적인 트리 구조를 하고 있는데, [그림 5-34]처럼 부분-전체의 상속 구조이다. 이와 같이 표현되는 조립 객체를 컴포지트 객체(composite object)라고 한다.

composite 패턴은 사용자가 단일 객체와 복합 객체 모두 동일하게 다루도록 한 것이다. 이런 형태는 재귀적인 구조로서, 마치 파일 구조에서 디렉토리 안에 파일이 존재할 수도 있고, 또 다른 디렉토리(서브 디렉토리)가 존재할 수 있는 것과 같다. 즉 composite 패턴은 그릇(디렉토리)과 내용물(파일)을 동일시해서 재귀적인 구조를 만들기 위한 설계 패턴이다.

 

 

컴포지트 패턴을 가장 잘 설명할 수 있는 예제는 파일과 디렉토리 관계이다. 가장 간단하게 파일과 디렉토리를 구현해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class File {
    
    private String name;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
    
    
}
 
public class Directory {
    
    private String name;
    private List<File> files;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void addFile(File file) {
        if(!files.contains(file)) files.add(file);
        else System.out.println("동일한 파일이 존재합니다.");
    }
    
}
cs

 

위와 같이 구현했다고 생각해보자. 얼핏보면 괜찮은 것 같다. 하지만 만약 디렉토리 밑에 디렉토리를 넣고 싶다면? 어떻게 해야할까? 여기서 생각해보자. 디렉토리 안에는 파일도 들어갈 수 있고 또 다른 디렉토리가 들어갈 수도 있다. 여기서 파일하나가 단수 객체라면 디렉토리는 복수 객체가 될 수 있다. 또한 최상위는 하나의 디렉토리로 이루어지고 그 밑으로 디렉토리 및 파일이 들어간다. 즉, 전체 관계가 하나의 디렉토리이고 그 밑에 부분이 디렉토리 또는 파일이 될 수 있다. 이렇게 단수 혹은 복수를 동일한 인터페이스로 다룰 수 있게 하는 전체-부분관계를 구현할때 가장 유용한 것이 컴포지트 패턴이다. 

 

컴포지트 패턴을 다시 클래스다이어그램으로 나타내면 아래와 같다.

 

 

Component - 구체적인 부분, 즉 Leaf 클래스와 전체에 해당하는 Composite 클래스에 공통 인터페이스를 제공한다.

Leaf - 구체적인 부분 클래스로 Composite 객체의 부품으로 설정한다.

Composite - 전체 클래스로 복수 개의 Component를 갖도록 정의한다. 그러므로 복수 개의 Leaf, 심지어 복수 개의 Composite 객체를 부분으로 가질 수 있다.

 

우리는 맨 처음의 그림과는 다르게 파일 시스템을 설계할 것이다. 파일 시스템은 추상적으로 보면 트리와 같은 구조를 가지고 있다. 즉, Component를 Node로 표현하고 Leaf로 File Composite로 Directory를 표현할 것이다. 바로 구현해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public abstract class Node {
    
    private String name;
    private int depth=0;
    
    public Node(String name) {
        this.name=name;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getDepth() {
        return depth;
    }
 
    public void setDepth(int depth) {
        this.depth = depth;
    }
    
    public abstract int getSize();
    public abstract void print();
}
 
public class File extends Node{
    
    private int size;
    
    public File(String name, int size) {
        super(name);
        this.size=size;
    }
 
    @Override
    public int getSize() {
        return this.size;
    }
 
    @Override
    public void print() {
        System.out.println("File - "+getName());
    }
    
}
 
public class Directory extends Node{
    
    private List<Node> nodes = new ArrayList<>();
    
    public Directory(String name) {
        super(name);
    }
    
    public void addNode(Node node) {
        nodes.add(node);
    }
    
    public void removeNode(Node node) {
        nodes.remove(node);
    }
    
    public int getSize() {
        int size = nodes.size();
        System.out.println("Directory size - "+size);
        return size;
    }
    
    public void print() {
        
        for(Node node : nodes) {
            node.print();
        }
        
    }
    
}
cs

 

완벽한 구현은 아니지만 파일 시스템을 컴포지트 패턴으로 구현 가능하다라는 정도만 알자!