이번 장에서는 상속남용 문제를 살펴보고, 런타임에서 객체를 디자인 하는 방법을 살펴봅니다.
디자인 원칙
클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다.
데코레이터 패턴에서는 객체에 추가적인 요건을 동적으로 첨가한다.
데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.
Component
ConcreteComponent
Decorator
ConcreteDecorator
import Foundation
//Beverage Protocol
protocol Beverage {
var description: String { get }
func getDescription() -> String
func cost() -> Double
}
//Decorator Protocol
protocol CondimentDecorator: Beverage {
func getDescription() -> String
}
//HouseBlend 커피
struct HouseBlend: Beverage {
internal var description: String
init() { self.description = "HouseBlend" }
func getDescription() -> String { description }
func cost() -> Double { 0.99 }
}
//모카 장식
struct Mocha: CondimentDecorator {
internal let beverage: Beverage
internal var description: String = "Mocha"
init(beverage: Beverage) { self.beverage = beverage }
func getDescription() -> String { beverage.getDescription() + " +Mocha" }
func cost() -> Double { 0.20 + beverage.cost() }
}
//휘핑크림 장식
struct Whip: CondimentDecorator {
internal let beverage: Beverage
internal var description: String = "Whip"
init(beverage: Beverage) { self.beverage = beverage }
func getDescription() -> String { beverage.getDescription() + " +Whip" }
func cost() -> Double { 0.05 + beverage.cost() }
}
//Main
let houseBlend = HouseBlend()
let mocha = Mocha(beverage: houseBlend)
let whip = Whip(beverage: mocha)
let whip2 = Whip(beverage: whip)
print("\(whip2.getDescription())" + " $\(whip2.cost())")