카테고리 없음
[헤드퍼스트 디자인패턴] 9-2. 컴포지트 패턴(Composite Pattern)
혀내
2023. 4. 30. 16:44
반응형
컴포지트 패턴(Composite Pattern)
객체를 트리구조로 구성해 트리 전체의 복합적인 객체와 개별 객체를 똑같은 방법으로 다룰 수 있도록 도와주는 패턴입니다.
- 메뉴, 서브메뉴, 서브서브메뉴로 구성된 트리구조 각각이 모두 복합 객체가 될 수 있습니다.
- 간단한 코드로도 똑같은 작업을 전체 메뉴 구조에 반복적으로 적용할 수 있습니다.
구조
1. Component 인터페이스: 트리에 들어가는 모든 요소들의 공통적인 인터페이스를 정의합니다.
2. Leaf 클래스: 트리의 기본 요소로, Composite에서 지원하는 기능을 구현합니다.
3. Composite 클래스:
- 자식이 있는 구성 요소로, 행동을 정의하고 자식 구성 요소를 저장하는 역할을 맡습니다.
- 요청을 받으면 작업을 자식 구성 요소에게 전달하고, 행동을 수행한 다음 최종 결과를 클라이언트에게 반환합니다.
4. Client 클래스: Component 인터페이스를 사용해 트리 내 모든 객체들을 조작할 수 있습니다.
컴포지트 패턴은 단일 책임 원칙을 깨는 대신 '투명성'을 확보하는 패턴입니다.
투명성이란 한 인터페이스에 자식을 관리하는 기능과 잎의 기능을 전부 넣어 클라이언트가 복합 객체와 잎을 똑같은 방식으로 처리할 수 있도록 만드는 것을 말합니다. 클라이언트의 입장에서는 어떤 원소가 복합 객체이거나, 잎인지 투명하게 확인할 수 있습니다.
예제
8-1. 반복자 패턴에서 사용했던 예제를 다시 살펴보겠습니다. PancakeMenu는 그대로 두되 DinerMenu에만 디저트 서브 메뉴를 추가하려고 합니다. 반복자 패턴을 적용한 기존 아키텍처로는 구현에 한계가 있을 것 같은데.. 컴포지트 패턴을 적용해 해결해볼까요?
MenuComponent 인터페이스 생성
public abstract class MenuComponent {
public void add(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public MenuComponent getChild(int i) {
throw new UnsupportedOperationException();
}
public String getName() {
throw new UnsupportedOperationException();
}
public String getDescription() {
throw new UnsupportedOperationException();
}
public double getPrice() {
throw new UnsupportedOperationException();
}
public boolean isVegeterian() {
throw new UnsupportedOperationException();
}
public void print() {
throw new UnsupportedOperationException();
}
}
메뉴판에 들어갈 메뉴 항목인 MenuItem 클래스 생성하기
public class MenuItem extends MenuComponent {
String name;
String description;
boolean vegeterian;
double price;
public MenuItem(String name, String description, boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public double getPrice() {
return price;
}
public boolean isVegeterian() {
return vegetarian;
}
public void print() {
...
}
복합 객체 클래스인 Menu 클래스 생성하기
public class Menu extends MenuComponent {
List<MenuComponent> menuComponents = new ArrayList<MenuComponent>();
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 menuComponents.get(i);
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public void print() {
System.out.println("\n" + getName());
System.out.println(", " + getDescription());
System.out.println("-----------------------------------");
for (MenuComponent menuComponent : menuComponents) {
menuComponent.print();
}
}
}
종업원이 새로 만든 메뉴 구조를 사용하도록 수정하기
public class Waitress {
MenuComponent allMenus;
public Waitress(MenuComponent allMenus) {
this.allMenus = allMenus;
}
public void printMenu() {
allMenus.print();
}
}
반응형