[디자인패턴] 데코레이터 패턴(Decorator Pattern)

Damsul·2023년 1월 10일
0

디자인패턴

목록 보기
3/15
post-thumbnail

기존 객체 수정 없이 새로운 책임(기능)을 동적으로 추가하고 싶을때 사용하는 구조패턴

출처 : 위키디피아

  • Component : 실질적인 인스턴스를 컨트롤하는 역할
  • ConcreteComponent : Component의 실질적인 인스턴스의 부분으로 책임의 주체의 역할
  • Decorator : Component와 ConcreteDecorator를 동일시 하도록 해주는 역할
  • ConcreteDecoreator : 실질적인 장식 인스턴스 및 정의이며 추가된 책임의 주체

예제

카페 음료를 만들 때마다 매번 해당하는 클래스들의 객체를 생성해 주어야 하는 문제가 있을 수 있습니다. 이를 해결하기 위해 카페 음료의 기본 재료인 에스프레소라는 틀을 추상적으로 가지고 카페 음료를 만들 때 들어가는 재료들로 장식하는 방식을 사용하는 것입니다.

  • Component

[Beverage.java]

public interface Beverage {
    String getName();
    int getPrice();
    String add();

    default void printPrice() {
        System.out.println("가격 " + getPrice() + "원");
    }

}
  • ConcreteComponent

[Espresso.java]

public class Espresso implements Beverage {
    @Override
    public String getName() {
        return "에스프레소";
    }

    @Override
    public int getPrice() {
        return 2000;
    }

    @Override
    public String add() {
        return getName();
    }
}
  • Decorator

[Decorator.java]

abstract public class Decorator implements Beverage {
    private final Beverage beverage;

    public Decorator(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String add() {
        return beverage.add();
    }

    @Override
    public int getPrice() {
        return beverage.getPrice();
    }
}
  • ConcreteDecoreator

[Water.java]

public class Water extends Decorator {
    public Water(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getName() {
        return "물";
    }

    @Override
    public int getPrice() {
        return super.getPrice() + 500;
    }

    @Override
    public String add() {
        return super.add() + " + " +getName();
    }
}

[Milk.java]

public class Milk extends Decorator {
    public Milk(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getName() {
        return "우유";
    }

    @Override
    public int getPrice() {
        return super.getPrice() + 1000;
    }

    @Override
    public String add() {
        return super.add() + " + " + getName();
    }
}

[Syrup.java]

public class Syrup extends Decorator {
    public Syrup(Beverage beverage) {
        super(beverage);
    }

    @Override
    public String getName() {
        return "시럽";
    }

    @Override
    public int getPrice() {
        return super.getPrice() + 500;
    }

    @Override
    public String add() {
        return super.add() + " + " +getName();
    }
}
  • Client

[BackStar.java]

public class BackStar {

    public static void main(String[] args) {
        Beverage espresso = new Espresso();
        System.out.println("에스프레소 : " + espresso.add());
        espresso.printPrice();

        Beverage americano = new Water(espresso);
        System.out.println("아메리카노 : " + americano.add());
        americano.printPrice();

        Beverage caffeLatte = new Milk(espresso);
        System.out.println("카페라떼 : " + caffeLatte.add());
        caffeLatte.printPrice();

        Beverage chocoLatte = new Milk(espresso);
        chocoLatte = new Syrup(chocoLatte);
        System.out.println("초코라떼 : " + chocoLatte.add());
        chocoLatte.printPrice();

    }
}
  • 실행 결과

장단점

  • 장점
    - 객체에 동적으로 기능 추가가 간단하게 가능하다.

  • 단점
    - 데코레이터 클래스가 계속 추가되어 클래스가 많아질 수 있다.
    - 껍질로 감싸는 형식이기 때문에 객체의 정체를 알기 힘들고 복잡해 질 수 있다.

profile
내 맘대로 작성하는 개발일지/ 작고 소중한 개발창고

0개의 댓글