복합 패턴 개요
복합 패턴은 객체들을 트리 구조로 구성하여 부분-전체 계층구조를 구현하는 패턴입니다. 이 패턴을 사용하면 클라이언트에서 개별 객체와 복합 객체를 동일하게 다룰 수 있습니다. 오늘은 이 패턴에 대해서 공부해보겠습니다.
뭐하는 패턴이지?
위의 구조를 보면 당최 뭐하는 패턴인지 감이 안잡힐 수 있습니다. 간단하게 말하면 복합객체와 단일객체를 동일한 타입을 취급해서 단순화시키는 것인데요. 예를들어 폴더 - 파일의 구조를 가진다고 했을때, 폴더와 파일을 하나의 객체로 동일하게 취급해서 구조를 단순화 시키는 것입니다. 폴더안에는 파일이 들어갈 수 있고, 폴더안에는 폴더가 들어갈 수 있는 구조를 생각했을 때 이걸 효과적으로 단일화 시킬 수 있다는 뜻이죠. 코드를 보면서 이해해보도록 하겠습니다.
복합 패턴의 구조
위의 사진에서 Leaf는 단일객체, Composite는 복합객체를 뜻합니다. 우리는 Leaf -> 파일, Composite -> 폴더로 치환해서 코드를 구현해보겠습니다.
public interface FileComponent {
int getSize();
String getTitle();
}
public class File implements FileComponent {
private final String title;
private final int size;
public File(String title, int size) {
this.title = title;
this.size = size;
}
@Override
public int getSize() {
return size;
}
@Override
public String getTitle() {
return title;
}
}
public class Folder implements FileComponent {
private final String title;
private final List<FileComponent> files = new ArrayList<>();
public Folder(String title) {
this.title = title;
}
@Override
public int getSize() {
int size = 0;
for (FileComponent file : files) {
size += file.getSize();
}
return size;
}
@Override
public String getTitle() {
return title;
}
public void add(FileComponent file) {
files.add(file);
}
public void remove(FileComponent file) {
files.remove(file);
}
}
FileComponent interface를 만들고 파일과 폴더에서 구현했습니다.
public static void main(String[] args) {
Folder folder1 = new Folder("폴더1");
folder1.add(new File("파일1", 300));
Folder folder2 = new Folder("폴더2");
folder2.add(new File("파일2", 1000));
folder2.add(new File("파일3", 500));
Folder folder3 = new Folder("폴더2");
folder1.add(folder2);
folder1.add(folder3);
System.out.println("folder1.getTitle() = " + folder1.getTitle()); // 폴더1
System.out.println("folder2.getSize() = " + folder1.getSize()); // 1800
}
폴더1을 만들고 파일1을 넣었습니다.
폴더2를 만들고 파일2와 파일3을 넣었습니다.
그리고 아무것도 들어있지않은 폴더3을 만들었습니다.
마지막으로 폴더1에 폴더2와 폴더3을 넣었습니다.
이제 folder1의 title과 size를 출력해보면 내부에 들어있는 모든 파일의 크기가 출력됩니다.
복합 패턴의 장단점
장점
- 클라이언트 코드를 단순화
- 새로운 종류의 구성요소를 쉽게 추가
- 전체-부분 관계를 표현하기 용이
단점
- 설계가 지나치게 일반화될 수 있음
- 제약사항을 추가하기 어려움
복합패턴을 이용해 메뉴시스템 구현
복합패턴에 대해서 배웠으니 이 패턴을 활용해서 메뉴시스템을 구현해보겠습니다.
public abstract class MenuComponent {
protected String name;
protected String description;
public MenuComponent(String name, String description) {
this.name = name;
this.description = description;
}
public abstract void print();
}
public class MenuItem extends MenuComponent {
private int price;
public MenuItem(String name, String description, int price) {
super(name, description);
this.price = price;
}
@Override
public void print() {
System.out.println(name + ": " + description + " - " + price + "원");
}
}
public class Menu extends MenuComponent {
private List<MenuComponent> menuComponents = new ArrayList<>();
public Menu(String name, String description) {
super(name, description);
}
public void add(MenuComponent menuComponent) {
menuComponents.add(menuComponent);
}
@Override
public void print() {
System.out.println("\n" + name + ": " + description);
System.out.println("--------------------");
for (MenuComponent menuComponent : menuComponents) {
menuComponent.print();
}
}
}
폴더 - 파일 구조와 동일하게 구현했습니다. 조금 다른게 있다면 interface -> abstract가 변경된게 있습니다만 무시해도됩니다.
public static void main(String[] args) {
// 메인 메뉴
Menu mainMenu = new Menu("메인 메뉴", "메뉴를 선택해주세요");
// 커피 메뉴
Menu coffeeMenu = new Menu("커피", "커피를 선택해주세요");
coffeeMenu.add(new MenuItem("아메리카노", "진한 에스프레소의 맛과 향을 부드럽게 즐길 수 있는 아메리칸 스타일의 커피입니다.", 4500));
coffeeMenu.add(new MenuItem("카메라떼", "진한 에스프레소에 우유를 넣어 풍부한 커피향을 부드럽게 즐실 수 있습니다.", 5200));
// 음식 메뉴
Menu foodMenu = new Menu("음식", "커피와 함께 즐길 음식을 선택해주세요");
foodMenu.add(new MenuItem("크로크무슈", "햄과 치즈를 차곡차곡 쌓아 올려 만든 프랑스식 샌드위치로 사르르 녹아내린 모짜렐라 치즈가 입안 가득 풍성한 맛", 4500));
foodMenu.add(new MenuItem("페스토 햄 파니니", "터키햄과 모짜렐라치즈를 두둑하게 채운 대중적인 파니니", 6500));
// 메인메뉴에 커피, 음식메뉴를 추가
mainMenu.add(coffeeMenu);
mainMenu.add(foodMenu);
// 전체 메뉴 출력
mainMenu.print();
}
메인 메뉴: 메뉴를 선택해주세요
--------------------
커피: 커피를 선택해주세요
--------------------
아메리카노: 진한 에스프레소의 맛과 향을 부드럽게 즐길 수 있는 아메리칸 스타일의 커피입니다. - 4500원
카메라떼: 진한 에스프레소에 우유를 넣어 풍부한 커피향을 부드럽게 즐실 수 있습니다. - 5200원
음식: 커피와 함께 즐길 음식을 선택해주세요
--------------------
크로크무슈: 햄과 치즈를 차곡차곡 쌓아 올려 만든 프랑스식 샌드위치로 사르르 녹아내린 모짜렐라 치즈가 입안 가득 풍성한 맛 - 4500원
페스토 햄 파니니: 터키햄과 모짜렐라치즈를 두둑하게 채운 대중적인 파니니 - 6500원
출력결과입니다.
마치며
복합 패턴은 트리 구조의 객체 구성을 다룰 때 매우 유용한 패턴입니다. 특히 전체-부분 관계를 표현해야 하는 상황에서 강력한 도구가 될 수 있습니다. 하지만 설계가 지나치게 일반화될 수 있다는 점을 주의해야 하며, 실제 요구사항에 맞게 적절히 제약을 추가하는 것이 중요합니다.
'디자인패턴 > 구조' 카테고리의 다른 글
자바(JAVA) - 경량 패턴(Flyweight Pattern) (0) | 2024.12.05 |
---|---|
자바[JAVA] - 퍼사드 패턴(Facade Pattern) (0) | 2024.11.09 |
자바[JAVA] - 데코레이터 패턴(Decorator Pattern) (0) | 2024.10.02 |
자바(JAVA) - 브릿지 패턴(Bridge Pattern) (0) | 2024.09.30 |
자바(JAVA) - 어댑터 패턴(Adapter Pattern) (0) | 2024.09.24 |