독서 기록/디자인패턴

[디자인 패턴] Composite Pattern

JoJobum 2022. 10. 24.

 Composite Pattern의 특징

트리와 같은 계층적인 정보에서

하위에 정보가 없는 리프노드, 자식이 있는 논 리프노드 가 있을 때,

이런 서로 다른 노드를 같은 인터페이스를 통하여 일관된 방식으로 프로그래밍할 수 있게 함 

 

public class MenuItem extends MenuComponent { String name;
	String description;
	boolean vegetarian;
	double price;
	public MenuItem(String name, String description, boolean vegetarian,
        double price) {
                   ...
	}
	public String getName() {
		return name; 
	}
	public String getDescription() { 
    	return description;
	}
	public double getPrice() {
		return price;
	}
	public boolean isVegetarian() { 
		return vegetarian;
	}
	public void print() {
		System.out.print(" " + getName());
		if (this.isVegetarian()) System.out.println("(v)");
			System.out.println(", " + getPrice()); 
		System.out.println(" --" + getDescription());
 	} 
}

 

 

public class Menu extends MenuComponent { 
	ArraryList menuComponents = new ArrayList(); 
	String name;
	String description;
	public Menu(String name, String description) { 
		this.name = name;
		this.description = description;
	}
	public void add(MenuComponent menuComponent) {
		menuComponents.add(menuComponent); }
	public void remove(MenuComponent menuComponent) { 
		menuComponents.remove(menuComponent);
	}
	public MenuComponent getChild(int i) {
		return (MenuComponent)menuComponents.get(i); 
	}
	public String getName() { 
		return name; 
	}
	public String getDescription () { 
		return description; 
	} 
	public void print() {
		Iterator iterator = menuComponents.iterator(); 
		while (iterator.hasNext()) {
			MenuComponent menuComponent = (MenuComponent)iterator.next();
			menuComponent.print();
		} 
	}
}

주목할 포인트

  • print에서 Iterator 사용
  • MenuComponent menuComponent = (MenuComponent)iterator.next(); 에서 MenuComponent가 Menu 일수도 있고 MenuItem일수도 있음, But 특정 클래스로 좁히면 좁힐수록 확장하기 어렵고 수정에 대처하기 어려운 문제(OCP 위반) 발생하기에 상위의 MenuComponent를 사용

 

 

 

전체 트리에서의  Iterator 만드는 법

트리 순회로 배운 preorder, inorder, postorder 방식을 Iterator에 접목시킴

=> 비슷한 방식으로 3차원 자료구조 혹은 n 차원 자료구조여도 선형으로 만들어줄 수 있는 알고리즘이 있다면 접목시켜 Iterator 시켜줄 수 있음

public class CompositeIterator implements Iterator { 
	Stack stack = new Stack();
	public CompositeIterator(Iterator iterator) {
		stack.push(iterator); 
	}
	public Object next() { 
		if (hasNext()) {
			Iterator iterator = (Iterator)stack.peek(); 
			MenuComponent component = (MenuComponent)iterator.next();
			// 루트노드의 자식노드들의 Iterator를 스택에 넣어준다
			if (component instance of Menu)
				stack.push(component.createIterator()); 
			return component;
		}
		else 
			return null; 
	}
	public boolean hasNext() {
		if (stack.empty()) 
			return false;
		Iterator iterator = (Iterator)stack.peek(); 
		if (!iterator.hasNext()) {
			stack.pop();
			return hasNext(); 
		} 
		else 
			return true;
	}
	public void remove() {
		throw new UnsupportedOperationException(); 
	}
}
public void printAllMenu() {
	Iterator iterator = allMenus.createIterator(); 
	while (iterator.hasNext()) {
		MenuComponent menuComponent =(MenuComponent)iterator.next(); 
		menuComponent.print();
	}
}

 

Decorator  패턴과 매우 유사

recursive composition을 갖고 있는 등...

But, 의도가 다르다 

Decorator 패턴은 서브 클래스를 추가하지 않고 책임을 추가할 수 있게 하는 패턴이였고

Commposite은 트리를 만들 수 있게 해주는 것

 

 

반응형

댓글