기록/패턴

Composite Pattern

jeongdalma 2020. 8. 5. 21:46

그릇과 내용물을 동일시해서 재귀적인 구조를 만들기 위한 디자인 패턴

 

Leaf(나뭇잎) 의 역할

Leaf는 '내용물'을 표시하는 역할을 하며 내부에는 다른 것을 넣을 수 없습니다.

예제 프로그램에서는 File클랙스가 이 역할을 합니다.

 

Composite(복합체) 의 역할

Composite는 '그릇'을 나타내는 역할을 하며 Leaf역할이나 Composite역할을 넣을 수 있습니다.

예제 프로그램에서는 Directory클래스가 이 역할을 합니다 .

 

Component의 역할

Leaf역할 과 Composite 역할을 동일시 하는 역할을 합니다.

Component는 Leaf역할과 Composite 역할에 공통적인 상위 클래스로 실현합니다.

예제 프로그램에서는 Entry클래스가 이 역할을 합니다.

 

Client(의뢰자) 의 역할

Composite패턴의 사용자입니다.

예제 프로그램에서는 Main 클래스가 이 역할을 합니다
Composite 역할이 포함하고 있는 Component 역할

(즉, Leaf역할이나 Composite 역할)을 부모에 대한 '자식'으로 간주합니다.

 

Main.java 

public class Main {
	public static void main(String[] args){
		try{
			System.out.println("Making root entries...");
			
			Directory rootdir = new Directory("root");					
			Directory bindir = new Directory("bin");				
			Directory tmpdir = new Directory("tmp");				
			Directory userdir = new Directory("user");				
            
			rootdir.add(bindir);										
			rootdir.add(tmpdir);									
			rootdir.add(userdir);										
																	
			bindir.add(new File("vi" , 10000));						
			bindir.add(new File("latex" , 20000));					
			rootdir.printList();									
																		
			System.out.println("");										
			System.out.println("Making user entries...");				
																		
			Directory Kim = new Directory("Kim");						
			Directory Lee = new Directory("Lee");	
			Directory Park = new Directory("Park");
													
			userdir.add(Kim);
			userdir.add(Lee);
			userdir.add(Park);
			
			Kim.add(new File("diary.html" , 100));			
			Kim.add(new File("Composite.java" , 200));	
														
			Lee.add(new File("memo.text" , 300));						
														
			Park.add(new File("game.doc" , 400));		
			Park.add(new File("junk.mail" , 500));		
																		
														
														
			rootdir.printList();						
		}												
		catch(FileTreatmentException e){								
		}
	}	
}		

File.java

public class File extends Entry {

	private String name;
	private int size;
	
	public File(String name , int size){
		this.name = name;
		this.size = size;
	}
	
	@Override
	public String getName() {
		return name;
	}
	@Override
	public int getSize() {
		return size;
	}
	@Override
	protected void printList(String prefix) {
		System.out.println(prefix + "/" + this);
	}
}

Directory.java

public class Directory extends Entry {

	private ArrayList directory = new ArrayList();
	private String name;

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

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

	@Override
	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;
	}
	
	@Override
	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);
		}
	}
}

Entry.java

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);	// prefix를 앞에 붙여서 종류를 표시

	public String toString(){
		return getName() +  " (" + getSize() + ")";
	}

}

Console

Making root entries...
/root (30000)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/user (0)

Making user entries...
/root (31500)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/user (1500)
/root/user/Kim (300)
/root/user/Kim/diary.html (100)
/root/user/Kim/Composite.java (200)
/root/user/Lee (300)
/root/user/Lee/memo.text (300)
/root/user/Park (900)
/root/user/Park/game.doc (400)
/root/user/Park/junk.mail (500)