Skip to content

TonnyL/Dash

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Dash

Design patterns in Kotlin and Swift.

In software engineering, a software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design.

Source: wikipedia.org

Table of Contents

In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns.

Source: wikipedia.org

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

Source: wikipedia.org

Kotlin example:

abstract class Subject {

    private val observers = mutableListOf<Observer>()

    fun addObserver(observer: Observer) {
        observers.add(observer)
    }

    fun removeObserver(observer: Observer) {
        observers.removeIf { it == observer }
    }

    protected fun notifyObserver() {
        observers.forEach {
            it.update()
        }
    }

    abstract fun doSomething()

}

interface Observer {

    fun update()

}

class ConcreteSubject : Subject() {

    override fun doSomething() {
        println("ConcreteSubject do something")
        notifyObserver()
    }

}

class ConcreteObserver1 : Observer {

    override fun update() {
        println("ConcreteObserver1 received message")
    }

}

class ConcreteObserver2 : Observer {

    override fun update() {
        println("ConcreteObserver2 received message")
    }

}

Kotlin usage:

val subject = ConcreteSubject()
val observer1 = ConcreteObserver1()
val observer2 = ConcreteObserver2()

subject.addObserver(observer1)
subject.addObserver(observer2)

subject.doSomething()

subject.removeObserver(observer1)

subject.doSomething()

Swift example:

class Subject {
    
    private var observers = Array<Observer>.init()
    
    func addObserver(_ observer: Observer) {
        observers.append(observer)
    }
    
    func removeObserver(_ index: Int) {
        observers.remove(at: index)
    }
    
    func notifyObserver() {
        observers.forEach {
            $0.update()
        }
    }
    
    func doSomething() {
        
    }
    
}

protocol Observer {
    
    func update()
    
}

class ConcreteSubject: Subject {
    
    override func doSomething() {
        print("ConcreteSubject do something")
        notifyObserver()
    }
    
}

class ConcreteObserver1: Observer {
    
    func update() {
        print("ConcreteObserver1 received message")
    }
    
}

class ConcreteObserver2: Observer {
    
    func update() {
        print("ConcreteObserver2 received message")
    }
    
}

Swift usage:

let subject = ConcreteSubject()
let observer1 = ConcreteObserver1()
let observer2 = ConcreteObserver2()

subject.addObserver(observer1)
subject.addObserver(observer2)

subject.doSomething()

subject.removeObserver(0)

subject.doSomething()

In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime.

Source: wikipedia.org

Kotlin example:

interface Strategy {

    fun calculate(a: Int, b: Int): Int

}

class AddStrategy : Strategy {

    override fun calculate(a: Int, b: Int): Int = a + b

}

class SubtractStrategy : Strategy {

    override fun calculate(a: Int, b: Int): Int = a - b

}

class Calculator(private val strategy: Strategy) {

    fun calculate(a: Int, b: Int): Int = strategy.calculate(a, b)

}

Kotlin usage:

val add = Calculator(AddStrategy())
val subtract = Calculator(SubtractStrategy())

println(add.calculate(1, 2))
println(subtract.calculate(1, 2))

Swift example:

protocol Strategy {
    
    func calculate(_ a: Int, _ b: Int) -> Int
    
}

final class AddStrategy: Strategy {
    
    func calculate(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
    
}

final class SubtractStrategy: Strategy {
    
    func calculate(_ a: Int, _ b: Int) -> Int {
        return a - b
    }
    
}

class Calculator {
    
    private let strategy: Strategy
    
    init(strategy: Strategy) {
        self.strategy = strategy
    }
    
    func calculate(_ a: Int, _ b: Int) -> Int {
        return strategy.calculate(a, b)
    }
    
}

Swift usage:

let add = Calculator(strategy: AddStrategy())
let subtract = Calculator(strategy: SubtractStrategy())

print(add.calculate(1, 2))
print(subtract.calculate(1, 2))

In object-oriented programming, the command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time.

Source: wikipedia.org

Kotlin example:

class Receiver {

    fun action() {
        println("do something")
    }

}

interface Command {

    fun execute()

}

class ConcreteCommand(private val receiver: Receiver) : Command {

    override fun execute() {
        receiver.action()
    }

}

class Invoker(private val command: Command) {

    fun action() {
        command.execute()
    }

}

Kotlin usage:

val receiver = Receiver()
val command = ConcreteCommand(receiver)
val invoker = Invoker(command)

invoker.action()

Swift example:

class Receiver {
    
    func action() {
        print("do something")
    }
    
}

protocol Command {
    
    func execute()
    
}

class ConcreteCommand: Command {
    
    private let receiver: Receiver
    
    init(receiver: Receiver) {
        self.receiver = receiver
    }
    
    func execute() {
        receiver.action()
    }
    
}

class Invoker {
    
    private let command: Command
    
    init(command: Command) {
        self.command = command
    }
    
    func action() {
        command.execute()
    }
    
}

Swift usage:

let receiver: Receiver = Receiver()
let command: Command = ConcreteCommand(receiver: receiver)
let invoker: Invoker = Invoker(command: command)

invoker.action()

The state pattern is a behavioral software design pattern that implements a state machine in an object-oriented way.

Source: wikipedia.org

Kotlin example:

interface State {

    fun handle(context: Context)

}

class Context {

    var state: State? = null

    fun request() {
        state?.handle(this)
    }

}

class StartState : State {

    override fun handle(context: Context) {
        println("Start state")
        context.state = this
    }

}

class StopState : State {

    override fun handle(context: Context) {
        println("Stop state")
        context.state = this
    }

}

Kotlin usage:

val context = Context()

context.state = StartState()
context.request()

context.state = StopState()
context.request()

Swift example:

protocol State {
    
    func handle(_ context: Context)
    
}

class Context {
    
    var state: State? = nil
    
    func request() {
        state?.handle(self)
    }
    
}

final class StartState: State {
    
    func handle(_ context: Context) {
        print("Start state")
        context.state = self
    }
    
}

final class StopState: State {
    
    func handle(_ context: Context) {
        print("Stop state")
        context.state = self
    }
    
}

Swift usage:

let context = Context()

context.state = StartState()
context.request()

context.state = StopState()
context.request()

In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects.

Source: wikipedia.org

Kotlin example:

class Level(level: Int) {

    var level = 1

    init {
        this.level = level
    }

}

class Request(var level: Level) {

    fun getLevel(): Int {
        return level.level
    }

}

class Response(val message: String) {

    init {
        println("Done")
    }

}

abstract class AbstractHandler {

    private var nextHandler: AbstractHandler? = null

    protected abstract val handlerLevel: Int

    fun handlerRequest(request: Request): Response? {
        var response: Response? = null

        if (handlerLevel == request.getLevel()) {
            response = response(request)
        } else {
            if (nextHandler != null) {
                println("To next handler")
                response = nextHandler?.handlerRequest(request)
            } else {
                println("No more request")
            }
        }

        return response
    }

    fun setNextHandler(handler: AbstractHandler) {
        nextHandler = handler
    }

    protected abstract fun response(request: Request): Response

}

class ConcreteHandlerA : AbstractHandler() {

    override val handlerLevel: Int
        get() = 0

    override fun response(request: Request): Response {
        println("Handled by ConcreteHandlerA")
        return Response("Response A")
    }

}

class ConcreteHandlerB : AbstractHandler() {

    override val handlerLevel: Int
        get() = 1

    override fun response(request: Request): Response {
        println("Handled by ConcreteHandlerB")
        return Response("Response B")
    }

}

Kotlin usage:

val handler1 = ConcreteHandlerA()
        val handler2 = ConcreteHandlerB()

        handler1.setNextHandler(handler2)
        val response1 = handler1.handlerRequest(Request(Level(0)))
        println("==== Response message -> ${response1?.message} ====")

        val response2 = handler1.handlerRequest(Request(Level(1)))
        println("==== Response message -> ${response2?.message} ====")

Swift example:

class Level {
    
    var level: Int = 1
    
    init(_ level: Int) {
        self.level = level
    }
    
}

class Request {
    
    var level: Level
    
    init(_ level: Level) {
        self.level = level
    }
    
    func getLevel() -> Int {
        return level.level
    }
    
}

class Response {
    
    let message: String
    
    init(_ message: String) {
        self.message = message
        print("Done")
    }
    
}

class AbstractHandler {
    
    private var nextHandler: AbstractHandler? = nil
    
    var handlerLevel: Int = 0
    
    func handlerRequest(_ request: Request) -> Response? {
        var resp: Response? = nil
        
        if handlerLevel == request.getLevel() {
            resp = response(request)
        } else {
            if nextHandler != nil {
                print("To next handler")
                resp = nextHandler?.handlerRequest(request)
            } else {
                print("No more request")
            }
        }
        
        return resp
    }
    
    func setNextHandler(_ handler: AbstractHandler) {
        nextHandler = handler
    }
    
    func response(_ request: Request) -> Response? {
        return nil
    }
    
}

class ConcreteHandlerA: AbstractHandler {
    
    override var handlerLevel: Int {
        get {
            return 0
        }
        set {
            
        }
    }
    
    override func response(_ request: Request) -> Response? {
        print("Handled by ConcreteHandlerA")
        return Response("Response A")
    }
    
}

class ConcreteHandlerB: AbstractHandler {
    
    override var handlerLevel: Int {
        get {
            return 1
        }
        set {
            
        }
    }
    
    override func response(_ request: Request) -> Response? {
        print("Handled by ConcreteHandlerB")
        return Response("Response B")
    }
    
}

Swift usage:

let handler1 = ConcreteHandlerA()
let handler2 = ConcreteHandlerB()

handler1.setNextHandler(handler2)
let response1 = handler1.handlerRequest(Request(Level(0)))
print("==== Response message -> \(response1?.message ?? "") ====")

let response2 = handler1.handlerRequest(Request(Level(1)))
print("==== Response message -> \(response2?.message ?? "") ====")

In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates.

Source: wikipedia.org

Kotlin example:

interface Visitor {

    fun visit(elementA: ConcreteElementA)

    fun visit(elementB: ConcreteElementB)

}

interface Visitable {

    fun accept(visitor: Visitor)

}

class ConcreteVisitorA : Visitor {

    override fun visit(elementA: ConcreteElementA) {
        elementA.operate()
    }

    override fun visit(elementB: ConcreteElementB) {
        elementB.operate()
    }

}

class ConcreteVisitorB : Visitor {

    override fun visit(elementA: ConcreteElementA) {
        elementA.operate()
    }

    override fun visit(elementB: ConcreteElementB) {
        elementB.operate()
    }

}

class ConcreteElementA : Visitable {

    override fun accept(visitor: Visitor) {
        visitor.visit(this)
    }

    fun operate() {
        println("ConcreteElementA ....")
    }

}

class ConcreteElementB : Visitable {

    override fun accept(visitor: Visitor) {
        visitor.visit(this)
    }

    fun operate() {
        println("ConcreteElementB ....")
    }

}

Kotlin usage:

val visitor1 = ConcreteVisitorA()
        val list1 = arrayListOf(ConcreteElementA(), ConcreteElementB())
        list1.forEach {
            it.accept(visitor1)
        }

        val visitor2 = ConcreteVisitorB()
        val list2 = arrayListOf(ConcreteElementB())
        list2.forEach {
            it.accept(visitor2)
        }

Swift example:

protocol Visitor {
    
    func visit(_ elementA: ConcreteElementA)
    
    func visit(_ elementB: ConcreteElementB)
    
}

protocol Visitable {
    
    func accept(_ visitor: Visitor)
    
}

class ConcreteVisitorA: Visitor {
    
    func visit(_ elementA: ConcreteElementA) {
        elementA.operate()
    }
    
    func visit(_ elementB: ConcreteElementB) {
        elementB.operate()
    }
    
}

class ConcreteVisitorB: Visitor {
    
    func visit(_ elementA: ConcreteElementA) {
        elementA.operate()
    }
    
    func visit(_ elementB: ConcreteElementB) {
        elementB.operate()
    }
    
}

class ConcreteElementA: Visitable {
    
    func accept(_ visitor: Visitor) {
        visitor.visit(self)
    }
    
    func operate() {
        print("ConcreteElementA ....")
    }
    
}

class ConcreteElementB: Visitable {
    
    func accept(_ visitor: Visitor) {
        visitor.visit(self)
    }
    
    func operate() {
        print("ConcreteElementB ....")
    }
    
}

Swift usage:

let visitor1 = ConcreteVisitorA()
let list1 = Array<Visitable>.init(arrayLiteral: ConcreteElementA(), ConcreteElementB())
list1.forEach {
    $0.accept(visitor1)
}

let visitor2 = ConcreteVisitorB()
let list2 = Array<Visitable>.init(arrayLiteral: ConcreteElementB())
list2.forEach {
    $0.accept(visitor2)
}

In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.

Source: wikipedia.org

The Builder design pattern is a creational design pattern, designed to provide a flexible design solution to various object creation problems in Object-Oriented software.

Source: wikipedia.org

Kotlin example:

data class Computer(
        var cpu: String? = null,
        var mainBoard: String? = null,
        var memory: String? = null,
        var graphicsCard: String? = null,
        var nic: String? = null,
        var soundCard: String? = null
)

abstract class Builder {

    private val computer = Computer()

    abstract fun setCpu()

    abstract fun setMainBoard()

    abstract fun setMemory()

    abstract fun setGraphicsCard()

    abstract fun setNic()

    abstract fun setSoundCard()

    open fun build(): Computer = computer

}

class AwesomeComputerBuilder : Builder() {

    private val awesomeComputer = Computer()

    override fun setCpu() {
        awesomeComputer.cpu = "đź‘Ť cpu"
    }

    override fun setMainBoard() {
        awesomeComputer.mainBoard = "đź‘Ť main board"
    }

    override fun setMemory() {
        awesomeComputer.memory = "đź‘Ť memory"
    }

    override fun setGraphicsCard() {
        awesomeComputer.graphicsCard = "đź‘Ť graphics card"
    }

    override fun setNic() {
        awesomeComputer.nic = "đź‘Ť nic"
    }

    override fun setSoundCard() {
        awesomeComputer.soundCard = "đź‘Ť sound card"
    }

    override fun build(): Computer = awesomeComputer

}

class JunkComputerBuilder : Builder() {

    private val junkComputer = Computer()

    override fun setCpu() {
        junkComputer.cpu = "đź‘Ž cpu"
    }

    override fun setMainBoard() {
        junkComputer.mainBoard = "đź‘Ž main board"
    }

    override fun setMemory() {
        junkComputer.memory = "đź‘Ž memory"
    }

    override fun setGraphicsCard() {
        junkComputer.graphicsCard = "đź‘Ž graphics card"
    }

    override fun setNic() {
        junkComputer.nic = "đź‘Ž nic"
    }

    override fun setSoundCard() {
        junkComputer.soundCard = "đź‘Ž sound card"
    }

    override fun build(): Computer = junkComputer

}

class Director {

    fun construct(builder: Builder) {
        builder.setCpu()
        builder.setMainBoard()
        builder.setMemory()
        builder.setGraphicsCard()
        builder.setNic()
        builder.setSoundCard()
    }

}

Kotlin usage:

val director = Director()
val awesomeBuilder = AwesomeComputerBuilder()
val junkBuilder = JunkComputerBuilder()

director.construct(awesomeBuilder)
val awesomeComputer = awesomeBuilder.build()
director.construct(junkBuilder)
val junkComputer = junkBuilder.build()

println(awesomeComputer)
println(junkComputer)

Swift example:

struct Computer {
    
    var cpu: String? = nil
    var mainBoard: String? = nil
    var memory: String? = nil
    var graphicsCard: String? = nil
    var nic: String? = nil
    var soundCard: String? = nil
    
}

class Builder {
    
    private var computer: Computer = Computer()
    
    func setCpu() {}
    
    func setMainBoard() {}
    
    func setMemory() {}
    
    func setGraphicsCard() {}
    
    func setNic() {}
    
    func setSoundCard() {}
    
    func build() -> Computer {
        return computer
    }
    
}

class AwesomeComputerBuilder: Builder {
    
    var awesomeComputer: Computer = Computer()
    
    override func setCpu() {
        awesomeComputer.cpu = "đź‘Ť cpu"
    }
    
    override func setMainBoard() {
        awesomeComputer.mainBoard = "đź‘Ť main board"
    }
    
    override func setMemory() {
        awesomeComputer.memory = "đź‘Ť memory"
    }
    
    override func setGraphicsCard() {
        awesomeComputer.graphicsCard = "đź‘Ť graphics card"
    }
    
    override func setNic() {
        awesomeComputer.nic = "đź‘Ť nic"
    }
    
    override func setSoundCard() {
        awesomeComputer.soundCard = "đź‘Ť sound card"
    }
    
    override func build() -> Computer {
        return awesomeComputer
    }
    
}

class JunkComputerBuilder : Builder {
    
    private var junkComputer: Computer = Computer()
    
    override func setCpu() {
        junkComputer.cpu = "đź‘Ž cpu"
    }
    
    override func setMainBoard() {
        junkComputer.mainBoard = "đź‘Ž main board"
    }
    
    override func setMemory() {
        junkComputer.memory = "đź‘Ž memory"
    }
    
    override func setGraphicsCard() {
        junkComputer.graphicsCard = "đź‘Ž graphics card"
    }
    
    override func setNic() {
        junkComputer.nic = "đź‘Ž nic"
    }
    
    override func setSoundCard() {
        junkComputer.soundCard = "đź‘Ž sound card"
    }
    
    override func build() -> Computer {
        return junkComputer
    }
    
}

class Director {
    
    func construct(_ builder: Builder) {
        builder.setCpu()
        builder.setMainBoard()
        builder.setMemory()
        builder.setGraphicsCard()
        builder.setNic()
        builder.setSoundCard()
    }
    
}

Swift usage:

let director = Director()
let awesomeBuilder = AwesomeComputerBuilder()
let junkBuilder = JunkComputerBuilder()

director.construct(awesomeBuilder)
let awesomeComputer: Computer? = awesomeBuilder.build()
director.construct(junkBuilder)
let junkComputer: Computer? = junkBuilder.build()

print(awesomeBuilder)
print(junkComputer)

In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.

Source: wikipedia.org

Kotlin example:

interface Factory {

    fun manufacture(): Product

}

interface Product {

    fun action()

}

class FactoryA : Factory {

    override fun manufacture(): Product = ProductA()

}

class FactoryB : Factory {

    override fun manufacture(): Product = ProductB()

}

class ProductA : Product {

    override fun action() {
        println("ProductA")
    }

}

class ProductB : Product {

    override fun action() {
        println("ProductB")
    }

}

Kotlin usage:

val factoryA = FactoryA()
factoryA.manufacture().action()

val factoryB = FactoryB()
factoryB.manufacture().action()

Swift example:

protocol Factory {
    
    func manufacture() -> Product
    
}

protocol Product {
    
    func action()
    
}

class FactoryA: Factory {
    
    func manufacture() -> Product {
        return ProductA()
    }
    
}

class FactoryB: Factory {
    
    func manufacture() -> Product {
        return ProductB()
    }
    
}

class ProductA: Product {
    
    func action() {
        print("ProductA")
    }
    
}

class ProductB : Product {
    
    func action() {
        print("ProductB")
    }
    
}

Swift example:

let factoryA = FactoryA()
factoryA.manufacture().action()

let factoryB = FactoryB()
factoryB.manufacture().action()

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object.

Source: wikipedia.org

Kotlin example:

object Singleton {
	
	fun action() {
        print("action")
    }
	
}

Kotlin usage:

Singleton.action()

Swift example:

class Singleton {
    
    private init() {}
    
    static private let INSTANCE: Singleton = Singleton()
    
    static func getInstance() -> Singleton {
        return INSTANCE
    }
    
    func action() {
        print("action")
    }
    
}

Swift usage:

Singleton.getInstance().action()

The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.

Source: wikipedia.org

Kotlin example:

interface AbstractFactory {

    fun manufactureContainer(): AbstractProduct

    fun manufactureMould(): AbstractProduct

}

interface AbstractProduct {

    fun action()

}

abstract class ContainerProduct : AbstractProduct

abstract class MouldProduct : AbstractProduct

class ContainerProductA : ContainerProduct() {

    override fun action() {
        println("ContainerProductA")
    }

}

class ContainerProductB : ContainerProduct() {

    override fun action() {
        println("ContainerProductB")
    }

}

class MouldProductA : MouldProduct() {

    override fun action() {
        println("MouldProductA")
    }

}

class MouldProductB : MouldProduct() {

    override fun action() {
        println("MouldProductB")
    }

}

class FactoryFA : AbstractFactory {

    override fun manufactureContainer(): AbstractProduct = ContainerProductA()

    override fun manufactureMould(): AbstractProduct = MouldProductA()


}

class FactoryFB : AbstractFactory {

    override fun manufactureContainer(): AbstractProduct = ContainerProductB()

    override fun manufactureMould(): AbstractProduct = MouldProductB()

}

Kotlin usage:

val factoryA = FactoryFA()
val factoryB = FactoryFB()

factoryA.manufactureContainer().action()
factoryA.manufactureMould().action()

factoryB.manufactureContainer().action()
factoryB.manufactureMould().action()

Swift example:

protocol AbstractFactory {
    
    func manufactureContainer() -> AbstractProduct
    
    func manufactureMould() -> AbstractProduct
    
}

protocol AbstractProduct {
    
    func action()
    
}

protocol ContainerProduct: AbstractProduct {
    
}

protocol MouldProduct: AbstractProduct {
    
}

class ContainerProductA: ContainerProduct {
    
    func action() {
        print("ContainerProductA")
    }
    
}

class ContainerProductB: ContainerProduct {
    
    func action() {
        print("ContainerProductB")
    }
    
}

class MouldProductA: MouldProduct {
    
    func action() {
        print("MouldProductA")
    }
    
}

class MouldProductB: MouldProduct {
    
    func action() {
        print("MouldProductB")
    }
    
}

class FactoryFA: AbstractFactory {
    
    func manufactureContainer() -> AbstractProduct {
        return ContainerProductA()
    }
    
    func manufactureMould() -> AbstractProduct {
        return MouldProductA()
    }
    
}

class FactoryFB: AbstractFactory {
    
    func manufactureContainer() -> AbstractProduct {
        return ContainerProductB()
    }
    
    func manufactureMould() -> AbstractProduct {
        return MouldProductB()
    }
    
}

Swift usage:

let factoryA = FactoryFA()
let factoryB = FactoryFB()

factoryA.manufactureContainer().action()
factoryA.manufactureMould().action()

factoryB.manufactureContainer().action()
factoryB.manufactureMould().action()

In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities.

Source: wikipedia.org

In software engineering, the adapter pattern is a software design pattern (also known as Wrapper, an alternative naming shared with the Decorator pattern) that allows the interface of an existing class to be used as another interface.

Source: wikipedia.org

Kotlin example:

interface Target {

    fun request()

}

open class Adaptee {

    fun specificRequest() {
        println("Specific request")
    }

}

class Adapter : Adaptee(), Target {

    override fun request() {
        this.specificRequest()
    }

}

Kotlin usage:

val adapter = Adapter()
adapter.specificRequest()

Swift example:

protocol Target {
    
    func request()
    
}

class Adaptee {
    
    func specificRequest() {
        print("Specific request")
    }
    
}

final class Adapter: Adaptee, Target {
    
    func request() {
        self.specificRequest()
    }
    
}

Swift usage:

let adapter = Adapter()
adapter.specificRequest()

In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.

Source: wikipedia.org

Kotlin example:

interface Component {

    fun action()

}

class ConcreteComponent : Component {

    override fun action() {
        println("Base function")
    }

}

abstract class Decorator(private val component: Component) : Component {

    override fun action() {
        component.action()
    }

}

class ConcreteDecoratorA(component: Component) : Decorator(component) {

    private val addedState: Int = 3

    override fun action() {
        println("ConcreteDecoratorA starts: Add new member addedState: $addedState")
        super.action()
        println("ConcreteDecoratorA ends")
    }

}

class ConcreteDecoratorB(component: Component) : Decorator(component) {

    private fun addedBehavior() {
        println("ConcreteDecoratorB starts: Add new function addedBehavior()")
    }

    override fun action() {
        addedBehavior()
        super.action()
        println("ConcreteDecoratorB ends")
    }

}

Kotlin usage:

var component: Component = ConcreteComponent()
        component.action()

        println("=============")

        component = ConcreteDecoratorA(component)
        component.action()

        println("=============")

        component = ConcreteDecoratorB(component)
        component.action()

        println("=============")

        component = ConcreteDecoratorA(ConcreteDecoratorB(ConcreteComponent()))
        component.action()

Swift usage:

protocol Component {
    
    func action()
    
}

class ConcreteComponent: Component {
    
    func action() {
        print("Base function")
    }
    
}

class Decorator: Component {
    
    private var component: Component
    
    init(_ component: Component) {
        self.component = component
    }
    
    func action() {
        component.action()
    }
    
}

class ConcreteDecoratorA: Decorator {
    
    private var component: Component
    private let addedState: Int = 3
    
    override init(_ component: Component) {
        self.component = component
        super.init(component)
    }
    
    override func action() {
        print("ConcreteDecoratorA starts: Add new member addedState: \(addedState)")
        
        super.action()
        print("ConcreteDecoratorA ends")
    }
    
}

class ConcreteDecoratorB : Decorator {
    
    private var component: Component
    
    override init(_ component: Component) {
        self.component = component
        super.init(component)
    }
    
    private func addedBehavior() {
        print("ConcreteDecoratorB starts: Add new function addedBehavior()")
    }
    
    override func action() {
        addedBehavior()
        super.action()
        print("ConcreteDecoratorB ends")
    }
    
}

Swift usage:

var component: Component = ConcreteComponent()
component.action()

print("=============")

component = ConcreteDecoratorA(component)
component.action()

print("=============")

component = ConcreteDecoratorB(component)
component.action()

print("=============")

component = ConcreteDecoratorA(ConcreteDecoratorB(ConcreteComponent()))
component.action()

A facade is an object that provides a simplified interface to a larger body of code, such as a class library.

Source: wikipedia.org

The Proxy design pattern is one of the twenty-three well-known GoF design patterns that describe how to solve recurring design problems to design flexible and reusable object-oriented software, that is, objects that are easier to implement, change, test, and reuse.

Source: wikipedia.org

License

Dash is under an MIT license. See the LICENSE for more information.

Releases

No releases published

Packages

No packages published