컴포지트 패턴(Composite Pattern)
개요
컴포지트 패턴Composite Pattern은 간단하게 말해 단일 객체Single Instance든 객체들의 집합Group of Instance이든 같은 방법으로 취급하는 것입니다. 다시 말해, 개별적인 객체들과 객체들의 집합간의 처리 방법의 차이가 없을 경우 사용하면 됩니다. 여기서 컴포지트Composite의 의미는 일부 또는 그룹을 표현하는 객체들을 트리 구조Tree Structures로 구성한다는 겁니다.
컴포지트 패턴의 활용
예를 하나 들어봅시다. 파일 시스템을 간단하게 구현해 본다고 생각해 봅시다. 먼저 필요한 것은 파일일겁니다. 그래서 파일 클래스를 만들었습니다. 자신의 이름을 가진 파일이겠죠.
class File { private String name; // ... }
그리고 파일들을 가질 수 있는 디렉토리 클래스가 필요하겠죠. 간단하게 만들어 줍니다.
class Directory { private String name; private List<File> children; // ... public void add(File file){ // ... } }
디렉토리 클래스는 자신의 이름과 파일들을 가질 수 있습니다. add() 메소드를 이용해 파일을 추가할 수도 있어요. 근데 이 구조로는 디렉토리 안에 디렉토리가 있는 것을 어떻게 표현해야 할까요?
우린 디자인 패턴을 공부하고 있으니까 멋있게 interface를 이용해서 구현해 봅시다.
/** Node 클래스는 기본적인 파일 및 디렉토리의 근간이라고 가정합니다. 모든 파일과 디렉토리는 이름을 가지고 있을테니 이름을 반환할 getName() 메소드를 가집니다. */ interface Node { public String getName(); } /** File 클래스는 Node 인터페이스를 구현하면 끝입니다. 자신은 자식 요소를 가질 필요가 없기 때문이죠. */ class File implements Node { private String name; // ... @Override public String getName(){ return name; } } /** Directory 클래스는 Node 인터페이스를 구현하는 것 외에도 자식 요소를 담아둘 List가 필요합니다. */ class Directory implements Node { private String name; private List<Node> children; // ... @Override public String getName(){ return name; } public void add(Node node) { children.add(node); } }
그럼 이제 한번 활용해 볼까요.
Directory dir = new Directory(); dir.add(new File()); // 디렉토리에 파일 하나를 삽입! dir.add(new Directory()); // 디렉토리에 디렉토리를 삽입! Directory secondDir = new Directory(); secondDir.add(dir); // 기존 루트 디렉토리를 새로 만든 디렉토리에 삽입!
간단하지만 트리 구조를 표현할 수 있는 파일 시스템을 만들었습니다!삭제 기능도 없고, 뭐도 없고 다 없지만... 그리고, 방금 구현한 코드가 컴포지트 패턴을 이용한 겁니다. 너무 간단하죠? :D
UML
실제로 컴포지트 패턴의 UML은 다음을 따릅니다.
┏━━━━━┓0..* ┃Component ┃━━━━━┓ ┗━━━━━┛child ┃ ▲ ┃ ┏━━━┻━━━┓ ┃ ┏━━━━━┓ ┏━━━━━┓ 1┃ ┃Leaf ┃ ┃Composite ┃◆┛ ┗━━━━━┛ ┗━━━━━┛parent
UML에 표현된 요소를 하나하나 살펴 봅시다.
Component
모든 표현할 요소들의 추상적인 인터페이스를 말합니다. 위의 예제 코드에서 Node 인터페이스가 이 역할을 담당하고 있었습니다.
Leaf
Leaf 요소는 Component로 지정된 인터페이스를 구현한 겁니다. 위의 예제 코드에서 File 클래스가 이 역할을 담당하고 있었습니다.
Composite
Composite 요소는 Component 요소를 자식으로 가집니다. 따라서 Component 요소를 관리하기 위한 메소드들을 추가적으로 구현해줘야겠죠. 위의 예제 코드에서는 Directory 클래스가 이 역할을 담당하고 있었습니다.
마무리
간단하게 컴포지트 패턴에 대해 알아 봤습니다. :)