본문 바로가기

책리뷰/헤드퍼스트 디자인패턴

헤드퍼스트 디자인패턴 - 데코레이터 패턴

728x90
반응형

목차

    초대형 커피전문점 주문시스템 만들기


     

    다양한 음료를 모두 포괄하는 주문 시스템을 만들려고 한다.

     

    만약 Beverage클래스에 우유, 두유, 모카, 휘핑크림을 추가하려고 할 때 인스턴스 변수를 추가하면

    메뉴마다 서브클래스를 만들고 각각 cost()를 구한 후 슈퍼클래스에서 구현한 cost()를 호출해 첨가물 비용을 더한다.

     

    인스턴스 추가로 발생하는 문제점

    • 첨가물 가격이 바뀔때마다 기존 코드를 수정해야함
    • 첨가물 종류가 많아지면 새로운 메서드를 구현해야하고, 슈퍼클래스의 cost()를 고쳐야 한다. 
    • 새로운 음료가 출시될 경우 첨가물이 들어가면 안되는 음료가 있을 수도 있다. (필요없는 메서드를 상속받음)
    • 고객이 모카를 두 번 주문 할 경우가 있을 수 있다.

    ☝🏻 디자인 원칙 

    클래스는 확장에는 열려있어야 하지만 변경에는 닫혀있어야 한다.(OCP)

     

    데코레이터 패턴 살펴보기


    특정 음료에서 시작해서 첨가물로 그 음료를 장식할 수 있다.

     

    1. DarkRoast 객체를 가져온다.
    2. Mocha 객체로 장식한다.
    3. Whip 객체로 장식한다.
    4.  cost()메소드를 호출한다. 첨가물 가격 계산은 해당 객체에게 위임한다.

     

     

    데코레이터 패턴 정리

    • 데코레이터의 슈퍼클래스는 자신이 장식하고 있는 객체의 슈퍼클래스와 같다.
    • 한 객체를 여러개의 데코레이터로 감쌀 수 있다.
    • 데코레이터는 자신이 감싸고 있는 객체와 같은 슈퍼클래스를 가지고 있기에 원래 객체가 들어갈 자리에 데코레이터 객체를 넣어도 상관없다.
    • 데코레이터는 자신이 장식하고 있는 객체에게 어떤 행동을 위임하는 일 말고도 추가 작업을 수행할 수 있다.
    • 객체는 언제든지 감쌀 수 있으므로 실행중에 데코레이터를 마음대로 적용할 수 있다.

     

    데코레이터 패턴 정의


    객체에 추가 요소를 동적으로 더할 수 있는 패턴.

    데코레이터를 사용하면 서브 클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있다.

     

     

     

    데코레이터 패턴 적용


    public abstract class Beverage {
        String description = "제목 없음";
    
        public String getDescription() {
            return description;
        }
    
        public abstract double cost();
        
    }
    // 데코레이터 객체가 자신이 감싸고 있는 객체가 들어갈 자리에
    //  자기가 들어갈 수 있어야 하므로 같은 인터페이스를 가진다
    public abstract class CondimentDecorator extends Beverage {
    
        Beverage beverage;
        public abstract String getDescription();
    
    }
    public class HouseBlend extends Beverage {
    
        public HouseBlend() {
            description = "house blend";
        }
    
        @Override
        public double cost() {
            return .89;
        }
        
    }
    public class Mocha extends CondimentDecorator {
    
        public Mocha(Beverage beverage) {
            this.beverage = beverage;
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + ", 모카";
        }
    
        @Override
        public double cost() {
            return beverage.cost() + .20;
        }
        
    }
    public class Whip extends CondimentDecorator {
    
        public Whip(Beverage beverage) {
            this.beverage = beverage;
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + ", 휘핑";
        }
    
        @Override
        public double cost() {
            return beverage.cost() + .20;
        }
        
    }
    public class StarbuzzCoffee {
        public static void main(String[] args) {
            Beverage beverage = new Espresso();
            System.out.println(beverage.getDescription() + " $" + beverage.cost());
    
            Beverage beverage2 = new HouseBlend();
            beverage2 = new Mocha(beverage2);
            beverage2 = new Mocha(beverage2);
            beverage2 = new Whip(beverage2);
    
            System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
        }
    }
    728x90
    반응형