8.    The Composite Pattern

개발자들은 종종 컴포넌트가 개별적인 객체로 간주될 수 있거나 일련의 객체를 표현할 수 있는 시스템을 개발하게 된다. Composite패턴은 위의 두 가지 경우에 모두 적용될 수 있도록 설계된 패턴이다.Composite패턴은 부분에서 전체에 이르는 계층 구조를 구축하거나Tree형 자료 명세 내역을 생성하기 위해 사용될 수 있다.예를 들어 디렉토리와 파일을 합해서 디렉토리 엔트리로 취급하듯이 그릇과 내용물을 같은 종류로 취급하는 경우다.이와 같이 특정 객체들과 그것들을 포함하는 객체들을 동일하게 다룰 수 있게 해주는 패턴을Composite패턴이라고 한다.

 

구조

사용자 삽입 이미지

 

역할

v     Leaf의 역할

내용물을 나타내는 역할,이 안에는 다른내용물을 넣을 수 없습니다.파일과 디렉토리 관계에서 보면파일에 해당합니다.

 

v     Composite의 역할

그릇을 나타내는 역할,이 안에는내용물과 다른그릇이 포함될 수 있습니다.파일과 디렉토리 관계에서디렉토리에 해당합니다.

 

v     Component의 역할

Leaf역할과Composite역할을 동일시하기 위한 일을 합니다. Component의 역할은Leaf역할과Composite역할의 공통의 상위 클래스로서 실현됩니다.

 

v     Client의 역할

Composite패턴의 이용자 입니다.

 

의도

전체부분을 표현하기 위해 객체들을 트리구조로 묶을 수 있다.클라이언트 코드는 각 개별적인 객체(부분)와 다른 객체를 포함하는 객체(전체)를 동일한 인터페이스를 통해 사용할 수 있다.

 

적용시기

전체와 부분을 동일하게 다루길 원할 때 적용 합니다.

결론

Composite패턴은 단순 객체 및 복잡한 객체의 계층 구조에 대한 클래스를 정리할 수 있게 하여 클라이언트의 프로그램에서는 모두 같은 종류로 나타낸다.노드와 리프가 같은 방식으로 관리되기 때문에 이렇게 단순화해서 클라이언트도 그것에 맞추어 간단해질 수 있다.

Composite패턴은 개발자의 컬렉션에 새로운 컴포넌트를 추가하기가 매우 쉬운데,해당 패턴이 유사한 프로그램밍 인터페이스를 지원하는 한 이것은 계속 유효하다.반면에Composite패턴은 시스템을 지나치게 일반화한다는 단점이 있다.이런 단점이 일반적으로 바람직하게 용인되는 경우 아마도 특정 클래스를 제한할 때 어려움을 겪게 될 것 이다.

 

구현상의 문제점

 

v     컴포넌트의 정렬일부 프로그램에서는 컴포넌트의 배열 순서가 중요한 요소로 작용할 수 있다.만약 부모 요소에 추가될 때의 정렬 순서와 실제 컴포넌트의 정렬 순서에 차이가 있을 경우 부모 요소는 반드시 추가된 컴포넌트들을 올바른 순서로 정렬하기 위해 별도의 작업을 수행해야 한다.예를 들어,원본Vector요소를 알파벳순으로 정렬한 후Enumerator에 수정된Vector정보를 되돌릴 수 있다.

v     케싱 결과일련의 자식 컴포넌트에서 연산되어야 하는 데이터를 종종 요청하는 경우 부모요소에서 연산 결과를 케싱하는 것이 도움이 될 수도 있다.그러나 해당 연산 적업이 상대적인 면에서 집중적으로 수행되어 개발자가 기본 데이터를 변경하지 않는다는 것을 확신할 수 있는 경우가 아닐 때는 이런 방법이 필요없을수도 있다.

 

예제소스

사용자 삽입 이미지

 

예제 소스

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() + ")";

   }

}

 

import java.util.Iterator;

import java.util.Vector;

 

public class Directory extends Entry {

   private String name;

   private Vector directory = new Vector();

   

   public Directory(String name) {

       this.name = name;

   }

   

   public String getName() {

       return name;

   }

   

   public int getSize() {

       int size = 0;

       Iterator it = directory.iterator();

       while (it.hasNext()) {

           Entry entry = (Entry)it.next();

           size += entry.getSize();

       }

       return size;

   }

   

   public Entry add(Entry entry) {

       directory.add(entry);

       return this;

   }

   

   protected void printList(String prefix) {

       System.out.println(prefix + "/" + this);

       Iterator it = directory.iterator();

       while (it.hasNext()) {

           Entry entry = (Entry)it.next();

           entry.printList(prefix + "/" + name);

       }

   }

}

 

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;

   }

   

   protected void printList(String prefix) {

       System.out.println(prefix + "/" + this);

   }

}

 

public class FileTreatmentException extends RuntimeException {

   public FileTreatmentException() {

   }

   

   public FileTreatmentException(String msg) {

       super(msg);

   }

}

 

public class mainClass {

 

   public static void main(String[] args) {

       mainClass client = new mainClass();

       client.exec();

   }

 

   public void exec() {

       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));

           

           

           Directory Kim = new Directory("Kim");

           Directory Lee = new Directory("Lee");

           Directory Kang = new Directory("Kang");

           

           usrdir.add(Kim);

           usrdir.add(Lee);

           usrdir.add(Kang);

           

           Kim.add(new File("diary.html", 100));

           Kim.add(new File("Composite.java", 200));

           Lee.add(new File("memo.tex", 300));

           Kang.add(new File("game.doc", 400));

           Kang.add(new File("junk.mail", 500));

           rootdir.printList();

       } catch(FileTreatmentException e) {

           e.printStackTrace();

       }

   }

}

 

관련패턴

사용자 삽입 이미지
      Command :매크로커맨드를 만들 때Composite패턴이 사용됩니다.

사용자 삽입 이미지
      Visitor : Composite를 순환하여 처리하는데 사용됩니다.

사용자 삽입 이미지
      Decorator : Composite는 그룻과,내용물을 동일시 하고, Decorator패턴은 장식과 내용물을 동일시합니다.

 

'Programming > Design Pattern' 카테고리의 다른 글

[펌] The Decorator Pattern  (0) 2006.01.21
[펌] The Bridge Pattern  (0) 2006.01.21
[펌] The Decorator Pattern  (0) 2006.01.21
[펌] The Builder Pattern  (0) 2006.01.21
[펌] The Prototype Pattern  (0) 2006.01.21

Posted by 영웅기삼
,