주어진 상황 및 용도에 따라 어떤 객체에 책임을 덧붙이는 패턴으로, 기능 확장이 필요할 때, 서브클래싱 대신 쓸 수 있는 유연한 대안이 될 수 있다.
데코레이터(Decortor) 뜻 그대로 원하는 클래스를 장식한다.
즉, Wrapping 한다 라고 생각할 수 있다.
Beverage
를 사용하여 커피를 만듭니다.
interface Beverage {
fun getDescription(): String {
return "Unknown Beverage"
}
fun cost(): Double
}
Interface 를 활용하면 실제 구현체를 서브 클래스로 위임할 수 있게 된다.
구현은 ConcreateComponent 에서 override
를 활용하여 구현하게 된다.
다이어 그램과 같이 Beverage
implements 하여 구현체를 작성하는 ConcreateComponent 만든다.
class Espresso : Beverage {
override fun getDescription(): String {
return "Espresso"
}
override fun cost(): Double {
return 1.99
}
}
class Decaf : Beverage {
override fun getDescription(): String {
return "Decaf Coffee"
}
override fun cost(): Double {
return 1.05
}
}
Beverage
의 구현체 클래스를 만들어 보았습니다.
Beverage는 인터페이스기 때문에 Client 에서 사용하기 위해 구현체 클래스를 만들어 주어야 합니다.
Client 에서 사용하기 위해 Espresso
, Decaf
클래스를 만들었습니다.
// 비슷한 카테고리를 한번에 처리하기 위해 abstract class 만들어 사용할 수 있다.
abstract class CondimentDecorator : Beverage {
abstract val beverage: Beverage
}
// 기본 Beverage 를 생성자로 받아서 행동을 추가하는 class 이다.
class Milk(override val beverage: Beverage) : CondimentDecorator() {
override fun getDescription(): String {
return beverage.getDescription() + ", Milk"
}
override fun cost(): Double {
return .10 + beverage.cost()
}
}
기본적인 Beverage
클래스를 Decorator 할 클래스를 만듭니다.
abstract class 로 만들어 Beverage
에서 사용하는 class 를 override 할 수 있도록 하고
Beverage
를 서브 클래스에서 사용하도록 강제합니다.
서브클래스에서는 기본 Beverage
의 값에 추가로 장식할 수 있도록 함수를 재정의합니다.
Decorator class 만들어 사용하게 되면, 원래 데이터가 Wrapping 되는 효과를 얻을 수 있습니다.
class AppCafe {
init {
val bw = System.out.bufferedWriter()
var beverage1: Beverage = Decaf()
bw.appendLine("1번 커피 주문")
bw.appendLine("${beverage1.getDescription()} $${beverage1.cost()}")
var beverage2: Beverage = HouseBlend()
beverage2 = Mocha(beverage2)
beverage2 = Mocha(beverage2)
beverage2 = Whip(beverage2)
bw.appendLine("2번 커피 주문")
bw.appendLine("${beverage2.getDescription()} $${beverage2.cost()}")
var beverage3: Beverage = Espresso()
beverage3 = Milk(beverage3)
beverage3 = Soy(beverage3)
beverage3 = Mocha(beverage3)
bw.appendLine("3번 커피 주문")
bw.appendLine("${beverage3.getDescription()} $${beverage3.cost()}")
bw.flush()
}
}
private fun main() {
AppCafe()
}
모든 데코레이터를 만들고 커피를 주문해보겠습니다.
1번 커피의 경우 디카페인 커피에 아무것도추가하지 않습니다.
2번 커피는 기본 블랜딩 + 2개의 모카 + 휘핑 으로 주문합니다.
3번 커피는 에스프레소 + 우유 + 두유 + 모카 로 주문합니다.
기본 Beverage 에 Decorator class 덮어 Wrapping 하면 Beverage 에 Decorator에서 추가한 작업이 (+) 되어 return 됩니다.
Decorator 하고 싶은 Target을 Interface로 정의하고 구현체 Class 추가로 만듭니다.
생성자로 Target Interface 를 받아 장식하고 싶은 부분을 override 를 사용하여 추가합니다.
Decortor 를 지난 Target 은 Wrapping 되어 내가 추가한 값이 저장됩니다.