본문 바로가기
소프트웨어공학/디자인 패턴

Composite Pattern Example code, Designing Menus with Composite .java | Design Pattern디자인 패턴

by javapp 자바앱 2021. 10. 27.
728x90

 

 

Designing Menus with Composite

 

 

Composite Pattern Diagram

 

Waitress

Waitress는 MenuComponent 인터페이스/추상 클래스 를 통해 Menu 와 Menuitems에 access 한다.

 

MenuComponent

Menu 와 MenuItem 의 interface를 나타낸다.

abstract class 를 통해 클래스 내에 원하는 기본 메소드 구현 제공

공통연산과 Menu 조작 연산으로 구성

공통연산 : getName, getDescription, getPrice, print

조작연산 : add, remove, getChild

 

 

MenuItem

Both Menu and Menus override print()

 

 

Menu

we’ll use the getName() andngetDescription() methods to return the name and description of the menu.

 

 

 


 

 

Implementing the MenuComponent

 

package Composite;

public abstract class MenuComponent
{
    // 공통 연산
    public String getName(){ throw new UnsupportedOperationException(); }
    public void print(){ throw new UnsupportedOperationException(); }
    public String getDescription() { throw new UnsupportedOperationException(); }

    // For Composite
    // 추상 클래스에서 추상 메소드와 , 메소드내에서 예외처리 하는 경우를 비교해봄.
    public abstract void add(MenuComponent menuComponent); // -->> 비추
    public MenuComponent getChild(int idx){ throw new UnsupportedOperationException(); } // -->> 추천, 해당기능이 필요없는 클래스에서 생성하지 않아도됨.
    public void remove(MenuComponent menuComponent) { throw new UnsupportedOperationException(); }

    // For Leaf
    public double getPrice(){ throw new UnsupportedOperationException(); }
}

 

MenuComponent provides default implementations for every method.

 

본래 add 메소드도 예외처리 구현했었지만 실험적으로 abstract 메소드로 정의하였다.

public void add(MenuComponent menuComponent) { throw new UnsupportedOperationException(); }

-->>    public abstract void add(MenuComponent menuComponent); 

 

the default implementation is UnsupportedOperationException.

 

MenuItem 이나 Menu 에서 메소드를 원하지 않는다면 사용하지 않아도 된다.

they can just inherit the default implementation.

 

 

 

 

Implementing the Menu Item

package Composite;

public class MenuItem extends MenuComponent
{
    String name, description; double price;

    public MenuItem(String name, String description, double price) {
        this.name = name;
        this.description = description;
        this.price = price;
    }

    // 공통 연산
    @Override
    public String getName() {
        return name;
    }
    @Override
    public String getDescription() {
        return description;
    }

    // 추상클래스에 추상메소드 정의시,
    // 특정메소드가 필요가 없는 경우에도 Override로 생성되어
    // 이중으로 메소드를 정의해야되는 번거로움이 있다.
    @Override
    public void add(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    } // ->> 해당 메소드를 추상클래스에서 일반 메소드로 변환시켜 정의하는 것이 좋다.

    @Override
    public void print() {
        System.out.print("" + getName());
        System.out.println(", " + getPrice());
        System.out.println(" --  "+ getDescription());
    }

    // Leaf
    @Override
    public double getPrice() {
        return price;
    }
}

MenuComponent를 상속하여 메소드를 재정의할 수 있다.

그렇지만 add 와 같은 원하지 않는 메소드를 재정의 해야하는 번거러움이 있다.

그것을 abstract class 에서  the default implementation (  throw new UnsupportedOperationException(); ) 

 

 

 

 

 

Implementing the Composite Menu

 

 

package Composite;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Menu extends MenuComponent
{
    List<MenuComponent> menuComponents = new ArrayList<>();

    String name, description;

    public Menu(String name, String description) {
        this.name = name;
        this.description = description;
    }

    // 공통 연산
    @Override
    public String getName() {
        return name;
    }
    @Override
    public String getDescription() {
        return description;
    }
    @Override
    public void print() {
        System.out.println(getName()+ " : "+getDescription());

        Iterator iterator = menuComponents.iterator();

        while(iterator.hasNext())
        {
            MenuComponent menuComponent = (MenuComponent) iterator.next();
            menuComponent.print(); // 각 child 에게 print 위임
        }
        System.out.println();
    }

    // For Composite
    @Override
    public void add(MenuComponent menuComponent) {
        menuComponents.add(menuComponent);
    }
    @Override
    public void remove(MenuComponent menuComponent) {
        super.remove(menuComponent);
    }
    @Override
    public MenuComponent getChild(int idx) {
        return super.getChild(idx);
    }
}

 

 

 

 

update the Waitress code

 

package Composite;

// Client
// Component 인터페이스만을 사용
public class Waitress
{
    MenuComponent allMenus;

    public Waitress(MenuComponent allMenus) {
        this.allMenus = allMenus;
    }

    public void printMenu(){
        allMenus.print();
    }
}

 

 

 

runtime

Head First Design Patterns

 

 

 

 

 

Now for the test drive

 

package Composite;

public class main {
    public static void main(String[] args) {
        // Let's first create all the menu objects

        MenuComponent pancakeHouseMenu = new Menu("Pancake House Menu", "Breakfast");
        MenuComponent dinerMenu = new Menu("Diner Menu", "Diner");
        MenuComponent cafeMenu = new Menu("Cafe Menu", "coffee");
        MenuComponent dessertMenu = new Menu("DESSERT MENU", "Dessert of course");

        MenuComponent allMenus = new Menu("All Menus", "All Menus combined");

        // Menu Component
        allMenus.add(pancakeHouseMenu);
        allMenus.add(dinerMenu);
        allMenus.add(cafeMenu);

        // add menu items here

        dinerMenu.add(new MenuItem(
                "Pasta",
                "Spaghetti with Marinara Sauce, and a slice of sourdough bread",
                8900 ));
        dinerMenu.add(dessertMenu);

        dessertMenu.add(new MenuItem(
                "Apple Pie",
                "Apple pie with a flakey crust, topped with vanilla icecream",
                15900));

        // add more menu items here
        Waitress waitress = new Waitress(allMenus);
        waitress.printMenu();
    }
}

 

실행 결과

 

 

 

 

 

 

책 참고 : Head First Design Patterns

댓글