ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 구조패턴 > 컴포지트 *
    기타/디자인패턴 2021. 2. 11. 10:09

     

    객체들을 트리 구조로 구성해 부분과 전체를 나타내는 계층 구조로 만들 수 있다.

    컴포지트 패턴을 이용하면 클라이언트에서 개별 객체와 다른 객체들로 구성된 복합객체(composite) 를 똑같은 방법으로 다룰 수 있다.

    부분-전체 계층구조란, 부분들이 모여있지만, 모든 것을 하나로 묶어서 전체로 다룰 수 있는 구조를 말한다.

    컴포지트 패턴을 이용하면 객체의 구성과 개별 객체를 노드로 가지는 트리 형태로 객체를 구축할 수 있다.

    이런 복합 구조를 사용하면 복합 객체와 개별 객체에 대해 똑같은 작업을 적용할 수 있다.

    즉, 대부분의 경우에 복합 객체와 개별 객체를 구분할 필요가 없어진다.

     

    팬케이크하우스, 객체식당, 카페 식당이 병합되고 객체식당의 메뉴 내에 디저트 메뉴도 새로 만들어 끼워넣는다고 해보자. 

    객체식당 - Menu (복합객체,Composite

    파스타,피자,리조또 - MenuItem (잎,Leaf)  

     

     

     

     

    public class MenuTestDrive {
        public static void main(String[] args) {
            MenuComponent pancakaHouse= new Menu("팬케이크하우스 메뉴", "아침");
            MenuComponent cafe = new Menu("카페 메뉴", "저녁");
    
            MenuComponent dessert = new Menu("디저트 메뉴", "디저트");        
            dessert.add(new MenuItem("초코 퍼지","케익",true,8000));
    
            MenuComponent diner = new Menu("객체식당 메뉴", "점심");
            diner.add(new MenuItem("파스타","토마토 소스",true,2000));
            //객체 식당에 디저트 메뉴를 추가! 
            diner.add(dessert);
    
            MenuComponent allmenus = new Menu("전체 메뉴","전체");
            allmenus.add(pancakaHouse);
            allmenus.add(diner);
            allmenus.add(cafe);
            
            Waitress waitress = new Waitress(allmenus);
            waitress.printMenu();
        }
    }
    /*
    name= 전체 메뉴, desc= 전체
    name= 팬케이크하우스 메뉴, desc= 아침
    name= 객체식당 메뉴, desc= 점심
    파스타, 토마토 소스
    name= 디저트 메뉴, desc= 디저트 **** 객체식당에 추가된 디저트 출력됨
    초코 퍼지, 케익
    name= 카페 메뉴, desc= 저녁
    */
    public abstract class MenuComponent {
        /**
         * MenuComponent 를 추가, 삭제, get 하기 위한 메서드
         * */
        public void add(MenuComponent menuComponent){  
        }
        public void remove(MenuComponent menuComponent){       
        }
        public MenuComponent getChild(int i){
            throw new UnsupportedOperationException();        
        }
        /**
         * menuItem 에서 작업 처리하기 위한 메서드
         * menu 에서도 사용사능
        */
        public String getName(){
            throw new UnsupportedOperationException();        
        }
        public String getDesc(){
            throw new UnsupportedOperationException();        
        }
        public double getPrice(){
            throw new UnsupportedOperationException();        
        }
        public boolean isVegetarian(){
            throw new UnsupportedOperationException();        
        }
        public void print(){}
    }
    public class MenuItem extends MenuComponent{
        String name;
        String desc;
        boolean vegetarian;
        double price;
    
        public MenuItem(String name,String desc,boolean vegetarian,double price){
            this.name = name;
            this.desc = desc;
            this.vegetarian = vegetarian;
            this.price = price;
        }
    
        @Override
        public String getName() {   return name;  }
    
        @Override
        public String getDesc() {    return desc;   }
        @Override
        public boolean isVegetarian() {   return vegetarian;  }
        @Override
        public double getPrice() {    return price;   }
       
        @Override
        public void print() {
            System.out.println(getName() + ", " + getDesc());
        }
    }
    public class Menu extends MenuComponent {
        List<MenuComponent> menuComponents = new ArrayList();
        String name;
        String desc;
    
        public Menu(String name, String desc){
            this.name = name;
            this.desc = desc;
        }
    
        public void add(MenuComponent menuComponent){
            menuComponents.add(menuComponent);
        }
        @Override
        public void remove(MenuComponent menuComponent) {
            menuComponents.remove(menuComponent);
        }
    
        @Override
        public MenuComponent getChild(int i) {
            return (MenuComponent) menuComponents.get(i);
        }
        @Override
        public String getName() {   return name;   }
        @Override
        public String getDesc() {   return desc;   }
        @Override
        public void print() {
            System.out.println("name= " + name + ", desc= " + desc); //전체 메뉴
    
    	// 전체 메뉴 내 팬케이크하우스, 객체식당-디저트, 카페 메뉴 출력
            Iterator<MenuComponent> it = menuComponents.iterator();
            while(it.hasNext()){
                MenuComponent menu = (MenuComponent) it.next();
                menu.print();
            }
    
        }
    }

     

    베지테리안 메뉴만 출력하고 싶다면? 

    Waitress 에 printVegetarian 을 추가해보자.

    가지고 있는 allmenus 에 있는 menuitem 에서 isVegitarian 확인을 위해 iterator 를 받을 필요가 있어진다.

    public class Waitress {
        MenuComponent allmenus;
        public Waitress(MenuComponent allmenus){
            this.allmenus = allmenus;
        }
    
        public void printMenu(){
            allmenus.print();
        }
    
        public void printVegeratian(){
            Iterator it = allmenus.createIterator();
    
            while(it.hasNext()){
                MenuComponent menu = (MenuComponent) it.next();
                if(menu.isVegetarian()){
                    menu.print();
                }
            }
        }    
    }

     

    public class CompositeIterator implements Iterator{
    
        Stack<Iterator<MenuComponent>> stack = new Stack<>();
    
        public CompositeIterator(Iterator iterator){
            stack.push(iterator);
            
        }
    
        @Override
        public boolean hasNext() {
            if(stack.isEmpty()) {
                return false;
            } else {
                Iterator<MenuComponent> it = stack.peek();
                
                if(it.hasNext()) {
                    return true;
                } else {
                    stack.pop();
                    return hasNext();
                }
            }   
        }
    
        @Override
        public Object next() {
            Iterator<MenuComponent> it = stack.peek();
            MenuComponent component = (MenuComponent) it.next();
            if(component instanceof Menu){
                stack.push(component.createIterator());
            }
            return component;
            
        }
        
    }
    public class Menu extends MenuComponent{
        List<MenuComponent> menuComponents = new ArrayList();
        String name;
        String desc;
    
        public Menu(String name, String desc){    ..    }
    
        public void add(MenuComponent menuComponent){   ..    }
        @Override
        public void remove(MenuComponent menuComponent) {..  }
    
        @Override
        public MenuComponent getChild(int i) {    ..    }
        @Override
        public String getName() {  ..    }
        @Override
        public String getDesc() { ..    }
        @Override
        public void print() {     ..    }
    
        @Override
        public Iterator<MenuComponent> createIterator() {
            return new CompositeIterator(menuComponents.iterator());
        }
    }
    public static void main(String[] args) {
    
            MenuComponent pancakaHouse= new Menu("팬케이크하우스 메뉴", "아침");
            MenuComponent cafe = new Menu("카페 메뉴", "저녁");
    
            MenuComponent dessert = new Menu("디저트 메뉴", "디저트");        
            MenuComponent diner = new Menu("객체식당 메뉴", "점심");
    
            MenuComponent allmenus = new Menu("전체 메뉴","전체");
            
            allmenus.add(pancakaHouse);
            allmenus.add(diner);
            allmenus.add(cafe);
    
    
            diner.add(new MenuItem("파스타","토마토 소스",true,2000));
            diner.add(new MenuItem("스테이크","소고기",false,2000));      
            diner.add(dessert);
      //      dessert.add(new MenuItem("초코 퍼지","케익",true,8000)); 이렇게 하면 베지테리안에 초코퍼지 2번 나옴!
            diner.add(new MenuItem("초코 퍼지","케익",true,8000));
          
            
            Waitress waitress = new Waitress(allmenus);
            System.out.println("전체");
            waitress.printMenu();
            System.out.println("채식");
            waitress.printVegeratian();
        }

     

     

     

    출처 : 

    Head First Design Patterns

     

     

     

     

     

    반응형

    '기타 > 디자인패턴' 카테고리의 다른 글

    행위패턴 > 이터레이터 *  (0) 2021.02.11
    행위패턴 > 커맨드 *  (0) 2021.02.11
    구조패턴 > 퍼싸드 *  (0) 2021.02.11
    구조패턴 > 데코레이터 *  (0) 2021.02.11
    구조패턴 > 어댑터 *  (0) 2021.02.11
Designed by Tistory.