There is very little difference between magic and art. It’s an act to create something from nothing.

The template method pattern is a behavioral design pattern that defines the program skeleton of an algorithm in a method, called template method, which defers some steps to subclasses. – Wiki

protocol MagicRecipe {
    var isDarkMagic: Bool { get }
    func makeMagic()
    func addSpecialIngredience()
    func testMagic()
}

//: create the template for making the Magic Recipe. All whiteMagic needs to be tested before being released.
extension MagicRecipe {
    final func makeMagic(){
        print("Starting the magic-making process...")
        addSpecialIngredience()
        if !isDarkMagic {
           testMagic()
        }
        let magicType = isDarkMagic ? "Dark Magic" : "White Magic"
        print("A new \(magicType) is created! \n")
    }
}

//: The magic recipe for getting love
 class MagicRecipeForLove: MagicRecipe {
    var isDarkMagic: Bool
    var name: String
    var description: String { return name }
    init(isDarkMagic: Bool = false, name: String){
        self.isDarkMagic = isDarkMagic
        self.name = name
        print("Creating the magic: \(name)")
    }
    func addSpecialIngredience() {
        let ingredience = isDarkMagic ? "black diamond" : "red diamond"
        print("Adding \(ingredience) as special ingredience")
    }
    func testMagic() {
        print("testMagicing \(name)")
    }
}

//: Sleep Magic is always bad (dark magic)
 class MagicRecipeForSleep: MagicRecipe {
    var isDarkMagic: Bool { return true }
    var name: String
    var description: String { return name }
    init(name: String){
        self.name = name
        print("Creating the magic: \(name)")
    }
    func addSpecialIngredience() {
        print("Adding tears from the black witch as special ingredience")
    }
    func testMagic() {
        print("testMagicing \(name)")
    }
}


let l1 = MagicRecipeForLove(name: "Long Lasting Love")
l1.makeMagic()
let l2 = MagicRecipeForLove(isDarkMagic: true, name: "Crazy Stupid Love")
l2.makeMagic()
let s1 = MagicRecipeForSleep(name: "Sleeping in Emptiness")
s1.makeMagic()
let s2 = MagicRecipeForSleep(name: "Sleeping and Dreaming")
s2.makeMagic()

template