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
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
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")
}
}
val subject = ConcreteSubject()
val observer1 = ConcreteObserver1()
val observer2 = ConcreteObserver2()
subject.addObserver(observer1)
subject.addObserver(observer2)
subject.doSomething()
subject.removeObserver(observer1)
subject.doSomething()
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")
}
}
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
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)
}
val add = Calculator(AddStrategy())
val subtract = Calculator(SubtractStrategy())
println(add.calculate(1, 2))
println(subtract.calculate(1, 2))
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)
}
}
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
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()
}
}
val receiver = Receiver()
val command = ConcreteCommand(receiver)
val invoker = Invoker(command)
invoker.action()
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()
}
}
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
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
}
}
val context = Context()
context.state = StartState()
context.request()
context.state = StopState()
context.request()
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
}
}
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
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")
}
}
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} ====")
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")
}
}
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
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 ....")
}
}
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)
}
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 ....")
}
}
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
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()
}
}
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)
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()
}
}
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
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")
}
}
val factoryA = FactoryA()
factoryA.manufacture().action()
val factoryB = FactoryB()
factoryB.manufacture().action()
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")
}
}
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
object Singleton {
fun action() {
print("action")
}
}
Singleton.action()
class Singleton {
private init() {}
static private let INSTANCE: Singleton = Singleton()
static func getInstance() -> Singleton {
return INSTANCE
}
func action() {
print("action")
}
}
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
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()
}
val factoryA = FactoryFA()
val factoryB = FactoryFB()
factoryA.manufactureContainer().action()
factoryA.manufactureMould().action()
factoryB.manufactureContainer().action()
factoryB.manufactureMould().action()
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()
}
}
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
interface Target {
fun request()
}
open class Adaptee {
fun specificRequest() {
println("Specific request")
}
}
class Adapter : Adaptee(), Target {
override fun request() {
this.specificRequest()
}
}
val adapter = Adapter()
adapter.specificRequest()
protocol Target {
func request()
}
class Adaptee {
func specificRequest() {
print("Specific request")
}
}
final class Adapter: Adaptee, Target {
func request() {
self.specificRequest()
}
}
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
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")
}
}
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()
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")
}
}
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
Dash is under an MIT license. See the LICENSE for more information.