• Category: structural
  • Type: object
  • Motivation: add responsibility to an object, provide alternative to sub-class for extending function

diagram

do {
    let coffee = MilkCoffee()
    print(coffee.description, coffee.price)
}
// <Component>
protocol Coffee
{
    var price: Float { get }
    var description: String { get }
}

// ConcreteComponent
class SimpleCoffee: Coffee
{
    var price: Float {
        10.0
    }

    var description: String {
        "coffee"
    }
}
// Decorator
protocol CoffeeDecorator: Coffee
{
    var coffee: Coffee {get set} // the key
}

// ConcreteDecorator
class MilkCoffee: CoffeeDecorator
{
    var coffee: Coffee = SimpleCoffee()

    var price: Float {
        coffee.price + 5.0
    }

    var description: String {
        coffee.description + " milk"
    }
}