Design-Patterns-Swift

Decorator

import UIKit

///Decorator Design Pattern main functions:
///conforms to the O of SOLID, Open for extension, close for modification
///to extend the codebase, to compose an object at runtime

///with out Decorator design pattern you would have to keep on modifying this Computer_ object!

///so if you want to add an external HDD
///or High Definition Monitor, you need to constantly modify your main component
///thus, this violates O in SOLID

///Best approach

//create a abstract component
protocol Computer{
    func description() -> String
    func price() -> Int
}

//lets create my main component now, this component will be wrapped by other decorator components
class BrandAComputer : Computer{

    func description() -> String {
        //return Components.Computer.rawValue
        return "Brand A Computer"
    }

    func price() -> Int {
        return 1000
    }
}

class ComputerDecorator : Computer{

    //The computer instance is use to forward request to the concrete computer object
    let computer : Computer

    init(computer : Computer) {
        self.computer = computer
    }


    func description() -> String {
        return computer.description()
    }

    func price() -> Int {
        computer.price()
    }

}


//first decorator is going to be an external HDD
class ExternalHDD : ComputerDecorator{
    override func description() -> String {
        return computer.description() + " with an external HDD"
    }

    override func price() -> Int {
        computer.price() + 500
    }

}


class Monitor : ComputerDecorator{
    override func description() -> String {
        return computer.description() + " and a 23 inch monitor"
    }

    override func price() -> Int {
        computer.price() + 280
    }

}

//you can recursively include or exclude decorator items.
//just keep your main component, which is been wrapped, in this case the Computer.

var myComputer : Computer = BrandAComputer()
//myComputer = ExternalHDD(computer : myComputer)
myComputer = Monitor(computer: myComputer)
print("\(myComputer.description()) and a price of \(myComputer.price())" )

///we can now add another component:


class BrandBComputer : Computer{
    func description() -> String {
        //return Components.Computer.rawValue
        return "Brand B Computer"
    }

    func price() -> Int {
        return 2200
    }
}

//and use the decorators already in place, or you can extend it even more.
myComputer = BrandBComputer()
//myComputer = ExternalHDD(computer : myComputer)
myComputer = Monitor(computer: myComputer)
print("\(myComputer.description()) and a price of \(myComputer.price())" )