데코레이터 패턴(Decorator Pattern)

wannabeking·2022년 10월 6일
0

디자인 패턴

목록 보기
4/14
post-thumbnail

해당 예시는 헤드 퍼스트 디자인 패턴을 참고했습니다.

음료와 토핑

카페에선 다양한 음료를 다양한 토핑을 추가하여 주문할 수 있다.

심지어 하나의 토핑도 아닌, 여러 토핑을 추가해서 말이다.

우리는 카페 시스템을 구현하기 위하여 Beverage라는 추상 클래스에서 Americano, Latte와 같은 기본적인 메뉴를 구현했다.


카페에선 모카 토핑이 새롭게 출시하여 기존 클래스 외 MochaAmericano, MochaLatte를 추가했다.


이번엔 자바칩 토핑이... 또.. 다시... JavaChipAmericano, JavaChipMochaAmericano...?


데코레이터 패턴은 이름만 들어도 이러한 상황에 적합해보이지 않은가?
그럼, 데코레이터 패턴에 대해 알아보자.



데코레이터 패턴

데코레이터 패턴은 위와 같은 상황에서 확장에 열리고 변경에 닫혀야 하는 OCP를 지키게 해줄 수 있다.

어떤 방식으로 지키게 해주냐면, 겹겹이 감싸는 방법을 사용하여 새로운 데코레이터가 추가돼도 소스코드에 변경이 없다.

코드를 살펴보자!


public abstract class Beverage {

    protected String description = "이름 없음";

    public String getDescription() {
        return description;
    }

    public abstract int getPrice();
}
public class Americano extends Beverage{

    public Americano() {
        this.description = "아메리카노";
    }

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

Beverage라는 추상 클래스를 만들고, 상속받는 Americano를 만들었다.
아메리카노, 카푸치노와 같은 음료의 베이스는 Beverage를 그대로 상속 받는다.


public abstract class CondimentDecorator extends Beverage {

    protected Beverage beverage;

    public abstract String getDescription();
}
public class Mocha extends CondimentDecorator {

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

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 모카";
    }

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

데코레이터 패턴의 핵심이다.

CondimentDecorator 추상 클래스에선 필드에 Beverage가 추가되었다.
따라서 아래와 같이 겹겹이 감쌀 수 있는 것이다.

Beverage beverage = new Mocha(new Americano());

또한 CondimentDecorator를 상속 받는 여러 클래스들을 추가적으로 생성하면 더 겹겹이 감쌀 수 있을 것이다.

그럼 psvm에서 출력을 확인해보자.


public static void main(String[] args) {
    Beverage beverage1 = new Americano();
    System.out.println(beverage1.getDescription() + " : " + beverage1.getPrice());
    beverage1 = new Mocha(beverage1);
    System.out.println(beverage1.getDescription() + " : " + beverage1.getPrice());

    Beverage beverage2 = new JavaChip(new Mocha(new Frappuccino()));
    System.out.println(beverage2.getDescription() + " : " + beverage2.getPrice());
}

필자는 베이스 음료로 Americano, Frappuccino를 각 5000원, 6000원으로 생성했다.

토핑으로는 MochaJavaChip을 각 500원으로 생성했다.

기본 아메리카노는 5000원, 모카 아메리카노는 5500, 모카 & 자바칩 프라푸치노는 7000원이 출력되는 것을 확인할 수 있다.


우리는 모카 자바칩 프라푸치노라는 메뉴를 만들 필요가 없었고, 새로운 토핑 클래스를 추가하기만 했다.

또한 음료에 추가할 토핑들을 동적으로 선택하였다.

즉, 데코레이터 패턴은 객체에 추가 요소를 동적으로 더할 수 있고 유연하게 기능을 확장할 수 있는 OCP를 지킨 디자인 패턴이다.


모든 소스코드는 여기에서 확인할 수 있다.



profile
내일은 개발왕 😎

0개의 댓글