Decorator

The decorator pattern allows us to add behavior to the individual object dynamically, without affecting the behavior of other objects from the same class. We can achieve this by wrapping the object into another instance. The following diagram shows a case like this:

The diagram contains the AmateurCoffeeMachine and ProfessionalCoffeeMachine classes, which implement the CoffeeMachine interface.

The following example shows how this pattern works:

interface CoffeeMachine {
val leftCoffeeMilliliters: Int
val leftMilkMilliliters: Int

fun makeCoffee(milliliters: Int): Coffee {
leftCoffeeMilliliters - milliliters
return Coffee(milliliters)
}
fun makeMilk(milliliters: Int): Milk {
leftMilkMilliliters - milliliters
return Milk(milliliters)
}
}

CoffeeMachine is an interface that defines the base functionality for coffee machines. Furthermore, the Coffee and Milk classes look like this:

class Milk(milliliters: Int)
class Coffee(milliliters: Int)

AmateurCoffeeMachine implements the CoffeeMachine interface and looks as follows:

class AmateurCoffeeMachine(
override val leftCoffeeMilliliters: Int,
override val leftMilkMilliliters: Int
) : CoffeeMachine

The ProfessionalCoffeeMachine class implements CoffeeMachine and uses an instance of the AmateurCoffeeMachine class as a delegate:

class ProfessionalCoffeeMachine(coffeeMachine: CoffeeMachine): CoffeeMachine by coffeeMachine {
fun makeLatte() = Latte(makeMilk(150), makeCoffee(50))
fun makeCappuccino() = Cappuccino(makeMilk(100), makeCoffee(70))
}

The following snippet demonstrates how to create an instance of the AmateurCoffeeMachine class and extend its functionality at runtime:

fun main(args: Array<String>) {
val coffeeMachine = AmateurCoffeeMachine(1000, 1000)
//.........
val professionalCoffeeMachine = ProfessionalCoffeeMachine(coffeeMachine)
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.247.68