어떤 객체에 여러가지 변수들이 추가되어야 하는 경우 어떻게 해야할까?

예를 들어 카페의 음료 클래스가 있다고 가정해보자.

Beverage 추상 클래스로 시작되어서 Coffee, Tea 등 다양한 음료 객체가 만들어질 수 있겠다.

여기에서 각 음료들에 휘핑 크림이나 초콜릿, 우유 등을 추가할 수 있고, 각각의 재료가 추가될 때마다 음료의 가격이 올라가게 된다.

가장 간단하게 이를 구현하는 방법은, 모든 재료의 가지수만큼 클래스를 만드는 것이겠다.

WhipedCreamAndMilkCoffee, MochaIceTea 등등.. 새로운 음료 종류나 재료가 추가된다면 클래스는 무수하게 많아지게 된다.

이러한 문제를 해결하기 위해서, 데코레이터 패턴을 도입할 수 있다.

각각의 음료들에 추가되는 재료들을 “장식”이라고 표현하고, 음료객체를 재료객체로 감싸게 되는 것이다.

예를 들면 다음과 같다.

모카 객체 [
    크림 객체 (
        커피 객체
    )
]

위와같이 구현하기 위해서는, 마지막 음료 객체를 제외한 모든 장식 객체 안에 “음료”타입의 인스턴스 변수를 가지고 있어야 한다.

만약 위 음료의 가격을 알기 위해서는, 가장 외부의 객체의 cost()메서드를 호출하면 되는데 이 메서드는 차례로 자기가 가지고 있는 “음료”타입의 인스턴스의 cost를 호출한 뒤, 자기의 가격을 더하여 반환해준다.

클래스 다이어그램은 다음과 같이 구성된다.

classDiagram
    Beverage <|-- Coffee
    Beverage <|-- Tea
    Beverage <|-- Decorator
    Decorator <|-- Mocha
    Decorator <|-- Cream
    Decorator <|-- Milk
    class Beverage{
      cost()
    }
    class Coffee{
      cost()
    }
    class Tea{
      cost()
    }
    class Decorator{
    }
    class Mocha{
        Beverage beverage
        cost()
    }
    class Cream{
        Beverage beverage
        cost()
    }
    class Milk{
        Beverage beverage
        cost()
    }

사용법 예시

Beverage beverage = new Coffee();
beverage = new Mocha(beverage);  // 위에서 만든 Coffee 객체를 Mocha 객체로 감쌌다.
beverage = new Cream(beverage);  // Coffee를 감싼 Mocha를 감싼 Cream 객체

// Cream -> Mocha -> Coffee 순으로 cost()를 호출하여 나온 결과값을
// 자기 자신의 가격에 더하여 반환한다.
System.out.println(beverage.cost());