Transcript 02. 예제 프로그램
Java로 배우는 디자인패턴 입문
Chapter 11. Composite
그릇과 내용물의 동일시
2004-1
01. Composite 패턴
컴퓨터의 파일 시스템
– 디렉토리(폴더) 안에 파일이나 또 다른 디렉토리가 존재한다.
– 디텍토리와 파일을 합쳐서, ‘디렉토리 엔트리’라고 한다.
재귀적인 구조
– 그릇 안에 내용물을 넣을 수도 있고, 작은 그릇을 넣을 수도 있
다. 작은 그릇 안에는 더 작은 그릇이나 내용물을 넣을 수도 있
다.
Composite 패턴
– 그릇과 내용물을 동일시해서 재귀적인 구조를 만드는 패턴
– composite: 혼합물, 복합물이라는 뜻
11. Composite
2
02. 예제 프로그램
파일과 디렉토리를 그림으로 표현하는 프로그램
11. Composite
3
02. 예제 프로그램
클래스 다이어그램
11. Composite
4
02. 예제 프로그램
기본 아이디어
– 트리 형태의 디렉토리 구조
– 클라이언트가
root에 대해서 getSize( )를 호출하면,
root
bin
dir2
a.txt
b.txt
– root는 자신의 내용물인 bin, tmp, usr에게
getSize( )를 호출한다.
– bin은 자신의 내용물인 dir2, a.txt, b.txt에게
getSize( )를 호출한다.
=> 재귀적 호출 이용
11. Composite
tmp
usr
5
02. 예제 프로그램
Entry 클래스
– 추상 클래스이고, 디렉토리 엔트리를 표현함
– File 클래스와 Directory 클래스를 하위 클래스로 가진다.
– 이름과 size를 가지고 있다.
– add( )
디렉토리나 파일을 넣을 때 호출되는 메소드
구현은 하위 클래스인 Directory 가 제공한다.
Entry 클래스에서는 이 메소드가 호출되면 예외를 발생시킨다.
– printList( ), printList(String) : 오버로드됨
호출될 때 인수의 모양에 따라 적절한 메소드가 실행됨
printList(String)는 protected로 하위 클래스에서만 접근 가능함
– toString( ) : 이름과 size를 문자열로 표현함
11. Composite
6
02. 예제 프로그램
File 클래스
– 파일을 표현하는 클래스
– name과 size 속성
– 생성자 File( ): 이름과 크기를 인자로 받아들임
– getName( ): 파일의 이름을 반환함
– getSize( ): 파일의 크기를 반환함
– PrintList(String) 구현
prefix와 자신의 문자열 표현을 ‘/’로 묶어서 표현함
아래의 식은 모두 동일하다
prefix + “/” + this
prefix + “/” + this.toString( )
prefix + “/” + toString( )
11. Composite
7
02. 예제 프로그램
Directory 클래스
– name 필드 존재
– size 필드는 존재하지 않는다.
– getSize( )에서 디렉토리 사이즈를 동적으로 계산해서 반환한다.
현재 디렉토리 클래스에 포함된 모든 요소(디렉토리 또는 파일)를
하나하나 꺼내서 그 사이즈를 합한다.
아래 코드에서, entry가 File의 인스턴스나 Directory의 인스턴스
중 어떤 것이라도 상관없다.
– 이유: entry는 Entry 타입으로 선언되어 있고, Entry는 File이나
Directory의 부모 클래스이기 때문에 둘 다 참조할 수 있다.
size += entry.getSize( );
entry가 디렉토리인 경우에는, 다시 이 디렉토리의 getSize( )가 재
귀적으로 호출된다. (Composite 패턴의 재귀적 구조와 일치함)
11. Composite
8
02. 예제 프로그램
Directory 클래스
– printList( )
getSize 메소드와 마찬가지고 디렉토리에 포함된 Entry의 printList
를 재귀적으로 호출한다.
entry가 File의 인스턴스인지, Directory의 인스턴스인지 상관없다.
– 그릇과 내용물이 동일시 된다.
11. Composite
9
02. 예제 프로그램
FileTreatmentException 클래스
– File에 add 메소드를 호출했을 때 발행하는 예외를 나타냄
– RuntimeException을 상속받아서 정의됨
– Entry 클래스에 add( ) 메소드가 정의되어 있고, File 클래스에
는 add( ) 메소드가 없다.
따라서, File 클래스에 대해서 add( ) 메소드가 호출되면, Entry로
부터 상속받은 add( )가 실행된다.
따라서, FileTreatmentException 예외가 발생된다.
11. Composite
10
02. 예제 프로그램
Main 클래스
– 교재 203 페이지와 같은 디렉토리 계층을 만든다.
– 그 후에, 이 디렉토리 구조를 출력한다.
rootdir.printList( );
재귀적으로, 디렉토리 안에 있는 요소(디렉토리나 파일)의
printList( ) 가 호출된다.
11. Composite
11
03. 등장 역할
Leaf(잎사귀) 역할
– ‘내용물’에 해당되는 역할
– 이 안에는 다른 것을 넣을 수 없다
– 예제에서는 File 클래스가 해당됨
Composite(복합체) 역할
– ‘그릇’을 나타내는 역할
– Leaf와 Composite을 넣을 수 있다
– 예제에서는 Directory 클래스가 해당됨
11. Composite
12
03. 등장 역할
Component의 역할
– Leaf 역할과 Composite 역할을 동일시 하기 위한 역할
– Leaf와 Composite의 상위 클래스로 구현됨
– 예제에서는 Entry 클래스가 해당됨
Client(의뢰자)의 역할
– 예제에서 Main 클래스가 해당됨
11. Composite
13
03. 등장 역할
Composite이 포함하고 있는 요소를 얻어 오기 위한 메소드
=> 이 메소드는 자신이 포함하고 있는 요소들의 getChild
를 재귀적으로 호출한다.
=> 예제에서는, getSize( )와 printList( )가 여기에 해당된다.
11. Composite
14
04. 독자의 사고를 넓혀주는 힌트
복수와 단수의 동일시
– Composite 패턴은, 그릇과 내용물을 동일시하는 패턴
그릇이, 또 다른 그릇의 내용물이 될 수 있다.
11. Composite
15
04. 독자의 사고를 넓혀주는 힌트
add를 어디에 두어야 하나?
– 방법1: Entry 클래스에서 구현하고, 에러로 처리한다.
예제 프로그램이 여기에 해당됨
– 방법2: Entry 클래스에서 구현하고, 아무것도 실행하지 않는다.
– 방법3; Entry 클래스에서 추상 메소드로 선언은 하지만, 구현은
하지 않는다.
하위 클래스에서 필요하면 정의하고, 필요하지 않으면 에러로 처
리한다.
– 방법4: Directory 클래스에만 넣는다.
이 방법은, Entry 형의 변수에 add할 때, Directory 형으로 일일이
타입캐스트(형변환)해야 하는 번거로움이 있다.
(Directory) entry.add( );
11. Composite
16
04. 독자의 사고를 넓혀주는 힌트
재귀적 구조는 여러 곳에서 등장한다.
– 예: 윈도 안에는 자식 윈도를 가진다.
– 일반적으로 트리 구조는 Composite 패턴에 속한다.
11. Composite
17
05. 관련 패턴
Command 패턴 (22장)
Visitor 패턴 (13장)
Decorator 패턴 (12장)
11. Composite
18
06. 요약
그릇과 내용물을 동일시하고, 재귀적인 구조를 형성하는
Composite 패턴
11. Composite
19
연습 문제
11. Composite
20
02. 여러 가지 그림 템플릿
클래스 다이어그램
factoryMethod 역할
class Factory {
public Product createProduct(String name) {
return new Product(name);
}
}
Factory와 Product 수정 없이, 다른 종류의 ‘제품’과 ‘공장’을 추가로 만들수 있다.
=> Main 클래스(클라이언트)에서는, TV 제품이 필요한 경우, TVFactory 객체를 생성한 후에
TVFactory 객체의 create( ) 메소드를 호출하기만 하면 된다.
11. Composite
21