2012-1
덕성여자대학교 정보미디어대학
교재: 자바언어로배우는디자인패턴입문(개정판)/YukiHiroshi저/김윤정역/영진닷컴
컴퓨터의 파일 시스템
– 디렉토리(폴더) 안에 파일이나 또 다른 디렉토리가 존재한다.
– 디텍토리와 파일을 합쳐서, ‘디렉토리 엔트리’라고 한다.
재귀적인 구조
– 그릇 안에 내용물을 넣을 수도 있고, 작은 그릇을 넣을 수도 있 다. 작은 그릇 안에는 더 작은 그릇이나 내용물을 넣을 수도 있 다.
Composite 패턴
– 그릇과 내용물을 동일시해서 재귀적인 구조를 만드는 패턴 – composite: 혼합물, 복합물이라는 뜻
파일과 디렉토리를 그림으로 표현하는 프로그램
클래스 다이어그램
File과 Directory는 둘 다 내용물(Entry)이다.
Directory는
내용물(Entry)로 구성된다.
기본 아이디어
– 트리 형태의 디렉토리 구조 – 클라이언트가
root에 대해서 getSize( )를 호출하면, – root는 자신의 내용물인 bin, tmp, usr에게 getSize( )를 호출한다.
– bin은 자신의 내용물인 dir2, a.txt, b.txt에게 getSize( )를 호출한다.
=> 재귀적 호출 이용
root
bin
tmp usr
a.txt
b.txt
dir2
Entry 클래스
– 추상 클래스이고, 디렉토리 엔트리를 표현함
– File 클래스와 Directory 클래스를 하위 클래스로 가진다.
– 이름과 size를 가지고 있다.
– add( )
디렉토리나 파일을 넣을 때 호출되는 메소드
구현은 하위 클래스인 Directory 가 제공한다.
Entry 클래스에서는 이 메소드가 호출되면 예외를 발생시킨다.
– printList( ), printList(String) : 오버로드됨
호출될 때 인수의 모양에 따라 적절한 메소드가 실행됨
printList(String)는 protected로 하위 클래스에서만 접근 가능함
– toString( ) : 이름과 size를 문자열로 표현함
File 클래스
– 파일을 표현하는 클래스 – name과 size 속성
– 생성자 File( ): 이름과 크기를 인자로 받아들임 – getName( ): 파일의 이름을 반환함
– getSize( ): 파일의 크기를 반환함 – PrintList(String) 구현
prefix와 자신의 문자열 표현을 ‘/’로 묶어서 표현함
아래의 식은 모두 동일하다
prefix + “/” + this
prefix + “/” + this.toString( ) prefix + “/” + toString( )
Directory 클래스 – name 필드 존재
– size 필드는 존재하지 않는다.
– getSize( )에서 디렉토리 사이즈를 동적으로 계산해서 반환한 다.
현재 디렉토리 클래스에 포함된 모든 요소(디렉토리 또는 파일)를 하나하나 꺼내서 그 사이즈를 합한다.
아래 코드에서, entry가 File의 인스턴스나 Directory의 인스턴스 중 어떤 것이라도 상관없다.
– 이유: entry는 Entry 타입으로 선언되어 있고, Entry는 File이나 Directory의 부모 클래스이기 때문에 둘 다 참조할 수 있다.
entry가 디렉토리인 경우에는, 다시 이 디렉토리의 getSize( )가 재귀적으로 호출된다. (Composite 패턴의 재귀적 구조와 일치함)
size += entry.getSize( );
Directory 클래스(계속)
root
bin
tmp usr
a.txt b.txt dir2
getSize() 호출
getSize() 호출
getSize() 호출
1
2
3
Directory 클래스(계속) – printList( )
getSize 메소드와 마찬가지로 디렉토리에 포함된 Entry의 printList를 재귀적으로 호출한다.
entry가 File의 인스턴스인지, Directory의 인스턴스인지 상관없다.
– 그릇과 내용물이 동일시 된다.
FileTreatmentException 클래스
– File에 add 메소드를 호출했을 때 발행하는 예외를 나타냄 – RuntimeException을 상속받아서 정의됨
실행 중에 발생하는 예외로서,
예외처리를 하지 않아도, 컴파일 에러가 발생하지 않는 예외이다.
– 코드 작성 시 try~catch문 사용하지 않아도 된다.
– Entry 클래스에 add( ) 메소드가 정의되어 있고, File 클래스에 는 add( ) 메소드가 없다.
따라서, File 클래스에 대해서 add( ) 메소드가 호출되면, Entry로 부터 상속받은 add( )가 실행된다.
따라서, FileTreatmentException 예외가 발생된다.
Main 클래스
– 교재 203 페이지와 같은 디렉토리 계층을 만든다.
– 그 후에, 이 디렉토리 구조를 출력한다.
재귀적으로, 디렉토리 안에 있는 요소(디렉토리나 파일)의 printList( ) 가 호출된다.
rootdir.printList( );
Leaf(잎사귀) 역할
– ‘내용물’에 해당되는 역할
– 이 안에는 다른 것을 넣을 수 없다 – 예제에서는 File 클래스가 해당됨
Composite(복합체) 역할 – ‘그릇’을 나타내는 역할
– Leaf와 Composite을 넣을 수 있다
– 예제에서는 Directory 클래스가 해당됨
Component의 역할
– Leaf 역할과 Composite 역할을 동일시 하기 위한 역할 – Leaf와 Composite의 상위 클래스로 구현됨
– 예제에서는 Entry 클래스가 해당됨
Client(의뢰자)의 역할
– 예제에서 Main 클래스가 해당됨
Composite이 포함하고 있는 요소를 얻어 오기 위한 메소드
복수와 단수의 동일시
– Composite 패턴은, 그릇과 내용물을 동일시하는 패턴
그릇이, 또 다른 그릇의 내용물이 될 수 있다.
add를 어디에 두어야 하나?
– 방법1: Entry 클래스에서 구현하고, 에러로 처리한다.
예제 프로그램이 여기에 해당됨
– 방법2: Entry 클래스에서 구현하고, 아무것도 실행하지 않는다.
– 방법3; Entry 클래스에서 추상 메소드로 선언은 하지만, 구현은 하지 않는다.
하위 클래스에서 필요하면 정의하고, 필요하지 않으면 에러로 처 리한다.
– 방법4: Directory 클래스에만 넣는다.
이 방법은, Entry 형의 변수에 add할 때, Directory 형으로 일일이 타입캐스트(형변환)해야 하는 번거로움이 있다.
((Directory)entry).add( );
재귀적 구조는 여러 곳에서 등장한다.
– 예: 윈도 안에는 자식 윈도를 가진다.
– 일반적으로 트리 구조는 Composite 패턴에 속한다.
Command 패턴 (22장)
Visitor 패턴 (13장)
Decorator 패턴 (12장)
그릇과 내용물을 동일시하고, 재귀적인 구조를 형성하는 Composite 패턴
각자 해 볼 것