Skip to content

Instantly share code, notes, and snippets.

@carlosypunto
Last active March 23, 2018 06:03
Show Gist options
  • Save carlosypunto/a179a9203b60c7b1c19357af717d0f54 to your computer and use it in GitHub Desktop.
Save carlosypunto/a179a9203b60c7b1c19357af717d0f54 to your computer and use it in GitHub Desktop.
Swift 2 Multiparadigm Decorator Pattern
// Decorable Protocol --------------------------------------------------------------------
protocol IBeverage {
func description() -> String
func cost() -> Double
}
extension IBeverage {
func printDescription() {
print(self.description() + " $\(self.cost())" )
}
}
// Decorator condiments Abstract Class ---------------------------------------------------
class Condiment: IBeverage {
let beverage: IBeverage
required init(beverage: IBeverage) {
self.beverage = beverage
}
func description() -> String {
fatalError("Not Implemented")
}
func cost() -> Double {
fatalError("Not Implemented")
}
}
// Functional IBeverage Protocol extension -----------------------------------------------
extension IBeverage {
func decorateWithCondiments(condimentsTypes: [Condiment.Type]) -> IBeverage {
return condimentsTypes.reduce(self) {
return $1.init(beverage: $0)
}
}
}
// Concrete Decorable Beverage Classes ---------------------------------------------------
class HouseBlend: IBeverage {
func description() -> String {
return "House blended coffee"
}
func cost() -> Double {
return 0.89
}
}
class DarkRoast: IBeverage {
func description() -> String {
return "Dark roast coffee"
}
func cost() -> Double {
return 0.99
}
}
class Espresso: IBeverage {
func description() -> String {
return "Espressso coffee"
}
func cost() -> Double {
return 1.99
}
}
// Concrete Decorador Condiments Classes -------------------------------------------------
class Milk: Condiment {
override func description() -> String {
return self.beverage.description() + ", with Milk"
}
override func cost() -> Double {
return self.beverage.cost() + 0.10
}
}
class Mocha: Condiment {
override func description() -> String {
return self.beverage.description() + ", with Mocha"
}
override func cost() -> Double {
return self.beverage.cost() + 0.20
}
}
class Soy: Condiment {
override func description() -> String {
return self.beverage.description() + ", with Soy"
}
override func cost() -> Double {
return self.beverage.cost() + 0.15
}
}
class Whip: Condiment {
override func description() -> String {
return self.beverage.description() + ", with Whip"
}
override func cost() -> Double {
return self.beverage.cost() + 1.00
}
}
// Simulation ----------------------------------------------------------------------------
// Without decoration
let beverage1 = Espresso()
beverage1.printDescription()
// Mutable variable (bad practice)
var beverage2: IBeverage = DarkRoast()
beverage2 = Mocha(beverage: beverage2)
beverage2 = Soy(beverage: beverage2)
beverage2 = Whip(beverage: beverage2)
beverage2.printDescription()
// functional complex way
let beverage3 = Whip(beverage: Mocha(beverage: Milk(beverage: DarkRoast())))
beverage3.printDescription()
// functional easy way
let beverage4 = HouseBlend().decorateWithCondiments([Mocha.self, Milk.self, Whip.self])
beverage4.printDescription()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment