Design Pattern | Composite Pattern (컴포즈 패턴)


Composite 패턴이란?

  • Composite라는 단어는 혼합 또는 복합이라는 의미이다.
  • Composite 패턴은 용기와 내용물을 동일화하여 재귀적인 구조를 만드는 방식이다.
  • 디렉토리와 파일을 함께 디렉토리 항목으로 취급하기 위해 컨테이너와 내용물을 같은 종류의 것으로 취급하는 것이 편리 할 수 ​​있다. 예를 들어, 용기 안에는 내용물을 넣어도 되고, 한층 더 용기를 넣는 것도 좋다. 이런 식으로 재귀 구조를 만들 수 있다.
  • GoF의 디자인 패턴에서는 구조와 관련된 디자인 패턴으로 분류된다.

Composite 패턴 예제 프로그램

디렉토리, 파일 목록을 표시하는 예제 프로그램이다.

Class Diagram
Composite Pattern Class Diagram

1. Entry 클래스

File과 Directory의 기본이 되는 클래스이다.

Entry.java

package com.devkuma.designpattern.structural.composite;

public abstract class Entry {

    public abstract String getName();

    protected abstract void printList(String prefix);

    public void printList() {
        printList("");
    }
}

2. File 클래스

파일을 나타내는 클래스이다.

File.java

package com.devkuma.designpattern.structural.composite;

public class File extends Entry {

    private String name;

    public File(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    protected void printList(String prefix) {
        System.out.println(prefix + "/" + name);
    }
}

3. Directory 클래스

디렉토리를 나타내는 클래스이다.

Directory.java

package com.devkuma.designpattern.structural.composite;

import java.util.ArrayList;
import java.util.Iterator;

public class Directory extends Entry {

    private String name;
    private ArrayList<Entry> directory = new ArrayList();

    public Directory(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    public Entry add(Entry entry) {
        directory.add(entry);
        return this;
    }

    @Override
    protected void printList(String prefix) {
        System.out.println(prefix + "/" + name);
        Iterator<Entry> it = directory.iterator();
        while (it.hasNext()) {
            Entry entry = it.next();
            entry.printList(prefix + "/" + name);
        }
    }
}

4. Main 클래스

메인 처리를 실행하는 클래스이다.

Main.java

package com.devkuma.designpattern.structural.composite;

public class Main {
    public static void main(String[] args) {

        Directory workspaceDir = new Directory("workspace");
        Directory compositeDir = new Directory("composite");
        Directory testDir1 = new Directory("test1");
        Directory testDir2 = new Directory("test2");
        workspaceDir.add(compositeDir);
        workspaceDir.add(testDir1);
        workspaceDir.add(testDir2);

        File directory = new File("Directory.java");
        File entity = new File("Entity.java");
        File file = new File("file.java");
        File main = new File("main.java");
        compositeDir.add(directory);
        compositeDir.add(entity);
        compositeDir.add(file);
        compositeDir.add(main);
        workspaceDir.printList();
    }
}

5. 실행 결과

/workspace
/workspace/composite
/workspace/composite/Directory.java
/workspace/composite/Entity.java
/workspace/composite/file.java
/workspace/composite/main.java
/workspace/test1
/workspace/test2

장점

모든 객체(File, Directory)는 공통의 추상 클래스를 가지고 있으므로, 클라이언트로에서 봤을 때, 어느 것이 File인가 Directory인지, 내용을 의식할 필요가 없고, 동일하게 취급할 수 있다.
또, 새로운 클래스(예: SymbolicLink)를 추가해도, 기본 클래스(Entry)의 인터페이스가 바뀌지 않으면, 클라이언트의 처리에는 영향을 주지 않는다.