1. 정의
- 다양한 객체에 새로운 기능을 추가한다. 단, 캡슐화가 깨지게 된다.
2. 예시
- 메뉴 복합 객체를 탐색하면서 깊이(Depth) 출력 기능을 추가한다.
💡 컴포지트 패턴 참고
3. 그림
4. 클래스 다이어그램
5. 코드
public class Client {
public static void main(String[] args){
Visitor visitor = new Visitor();
MenuComponent breakfast = new Menu("아침 메뉴", "08:00~11:00", visitor);
MenuComponent lunch = new Menu("점심 메뉴", "12:00~17:00", visitor);
MenuComponent dinner = new Menu("저녁 메뉴", "18:00~23:00", visitor);
MenuComponent all = new Menu("전체 메뉴", "00:00~23:59", visitor);
all.add(breakfast);
all.add(lunch);
all.add(dinner);
// 메인
breakfast.add(new MenuItem("시리얼", "요거트", 4_000, visitor));
breakfast.add(new MenuItem("식빵", "딸기쨈", 3_000, visitor));
lunch.add(new MenuItem("팬케이크", "메이플 시럽", 6_000, visitor));
dinner.add(new MenuItem("불고기", "국내산", 15_000, visitor));
dinner.add(new MenuItem("비빔밥", "국내산", 10_000, visitor));
// 디저트
MenuComponent lunchDessert = new Menu("점심 디저트", "12:00~17:00", visitor);
lunchDessert.add(new MenuItem("커피", "콜롬비아", 1_500, visitor));
lunch.add(lunchDessert);
MenuComponent dinnerDessert = new Menu("저녁 디저트", "18:00~23:00", visitor);
dinnerDessert.add(new MenuItem("포도", "", 1_000, visitor));
dinnerDessert.add(new MenuItem("딸기", "", 1_000, visitor));
dinner.add(dinnerDessert);
all.print();
}
}
/* 출력
------ depth : 0 ------
[전체 메뉴](00:00~23:59)
------ depth : 1 ------
[아침 메뉴](08:00~11:00)
시리얼(요거트) : 4000
식빵(딸기쨈) : 3000
------ depth : 2 ------
[점심 메뉴](12:00~17:00)
팬케이크(메이플 시럽) : 6000
------ depth : 3 ------
[점심 디저트](12:00~17:00)
커피(콜롬비아) : 1500
------ depth : 4 ------
[저녁 메뉴](18:00~23:00)
불고기(국내산) : 15000
비빔밥(국내산) : 10000
------ depth : 5 ------
[저녁 디저트](18:00~23:00)
포도() : 1000
딸기() : 1000
*/
public class Visitor {
private int depth = 0;
public void getDepth(){
System.out.println("------ depth : " + (depth++) + " ------");
}
}
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 int getPrice(){
throw new UnsupportedOperationException();
}
public void print(){
throw new UnsupportedOperationException();
}
}
// Leaf Node
public class MenuItem extends MenuComponent {
String name, description;
int price;
Visitor visitor;
public MenuItem(String name, String description, int price, Visitor visitor) {
this.name = name;
this.description = description;
this.price = price;
this.visitor = visitor;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public int getPrice() {
return price;
}
@Override
public void print() {
System.out.println(name + "("+ description +")" + " : " +price);
}
}
import java.util.ArrayList;
import java.util.List;
// Node
public class Menu extends MenuComponent {
List<MenuComponent> component = new ArrayList<>();
String name;
String description;
Visitor visitor;
public Menu(String name, String description, Visitor visitor) {
this.name = name;
this.description = description;
this.visitor = visitor;
}
@Override
public void add(MenuComponent menuComponent) {
component.add(menuComponent);
}
@Override
public void remove(MenuComponent menuComponent) {
component.remove(menuComponent);
}
@Override
public MenuComponent getChild(int i) {
return component.get(i);
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public void print() {
visitor.getDepth(); // vistor의 depth()사용
System.out.println("["+name+"]" + "("+ description +")");
for (MenuComponent menuComponent : component) {
menuComponent.print();
}
}
}
https://github.com/kang-seongbeom/design_pattern
💡 Github에서 디자인 패턴 코드를 볼 수 있습니다.
6. 설명
- 기존의 메뉴 복합 객체에서 Visitor만 추가해 준 것 이외에 바뀐것이 없다.
- 새로운 기능을 추가하고 싶으면, 구조 변경 없이 Visitor 내부에 추가해 사용하면 된다.
- 단, 로직이 메뉴와 비지터로 분산되서 저장되기 때문에 캡슐화가 깨진다.
💡 비지터 패턴은 거의 필요하지 않지만, 한 번 필요해지면 비지터 패턴 밖에 답이 없다고 한다. (아마 계층 구조가 너무 복잡해서 새로운 기능을 추가하기 위해 비지터 패턴을 사용하는게 아닐까 싶다.)
'디자인 패턴' 카테고리의 다른 글
디자인 패턴 - 프로토타입 패턴(Prototype Pattern) (0) | 2022.11.18 |
---|---|
디자인 패턴 - 메멘토 패턴(Memento Pattern) (0) | 2022.11.18 |
디자인 패턴 - 중재자 패턴(Mediator Pattern) (0) | 2022.11.18 |
디자인 패턴 - 플라이웨이트 패턴(Flyweight Pattern) (0) | 2022.11.18 |
디자인 패턴 - 빌더 패턴(Builder Pattern) (0) | 2022.11.18 |