👷 Source items are maintained by @nsmeme (Oktawian Chojnacki).

🇨🇳 Chinese version edited and translated by @binglogo.

print("Welcome!" )Copy the code

directory

Behavioral pattern Creation pattern Structural mode
🐝 Chain Of Responsibility 🌰 Abstract Factory 🔌 Adapter
👫 Command Command 👷 Builder 🌉 Bridge Bridge
🎶 Interpreter 🏭 Factory Method Factory Method The Composite 🌿 combination
🍫 Iterator Iterator 🃏 Prototype Prototype 🍧 modified Decorator
💐 Mediator 💍 Singleton Singleton 🎁 exterior Facade
💾 Memento 🍃 Flyweight Flyweight
👓 Observer ☔ Protection Proxy
🐉 State State 🍬 Virtual Proxy Virtual Proxy
💡 Strategy Strategy
🏃 Visitor Visitor

Behavioral pattern

In software engineering, behavioral patterns are a type of design patterns used to identify common communication patterns between objects and implement them. This allows for increased flexibility in these communications.

Source: Wikipedia

🐝 Chain Of Responsibility

The chain of responsibility pattern is a software design pattern in object-oriented programming, which contains some command objects and a series of processing objects. Each processing object determines which command objects it can process, and it knows how to pass command objects that it cannot process to the next processing object in the chain.

Example:

protocol Withdrawing {
    func withdraw(amount: Int) -> Bool
}

final class MoneyPile: Withdrawing {

    let value: Int
    var quantity: Int
    var next: Withdrawing?

    init(value: Int, quantity: Int, next: Withdrawing?) {
        self.value = value
        self.quantity = quantity
        self.next = next
    }

    func withdraw(amount: Int) -> Bool {

        var amount = amount

        func canTakeSomeBill(want: Int) -> Bool {
            return (want / self.value) > 0
        }

        var quantity = self.quantity

        while canTakeSomeBill(want: amount) {

            if quantity == 0 {
                break
            }

            amount -= self.value
            quantity -= 1
        }

        guard amount > 0 else {
            return true
        }

        if let next = self.next {
            return next.withdraw(amount: amount)
        }

        return false
    }
}

final class ATM: Withdrawing {

    private var hundred: Withdrawing
    private var fifty: Withdrawing
    private var twenty: Withdrawing
    private var ten: Withdrawing

    private var startPile: Withdrawing {
        return self.hundred
    }

    init(hundred: Withdrawing,
           fifty: Withdrawing,
          twenty: Withdrawing,
             ten: Withdrawing) {

        self.hundred = hundred
        self.fifty = fifty
        self.twenty = twenty
        self.ten = ten
    }

    func withdraw(amount: Int) -> Bool {
        return startPile.withdraw(amount: amount)
    }
}Copy the code

usage

Let ten = MoneyPile(value: 10, quantity: 6, next: nil) let twenty = MoneyPile(value: 10, quantity: 6, next: nil) 20, quantity: 2, next: ten) let fifty = MoneyPile(value: 50, quantity: 2, next: twenty) let hundred = MoneyPile(value: Var ATM = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten) atm.withdraw(amount: 310) // Cannot because ATM has only 300 atm.withdraw(amount: 100) // Can withdraw - 1x100Copy the code

👫 Command

Command pattern is a design pattern that attempts to represent actual actions in terms of objects. Command objects can encapsulate actions and their parameters, so that these actions can be:

  • Repeated many times
  • Cancel (if the object has an implementation)
  • Cancel and do it again

Example:

protocol DoorCommand {
    func execute() -> String
}

final class OpenCommand: DoorCommand {
    let doors:String

    required init(doors: String) {
        self.doors = doors
    }
    
    func execute() -> String {
        return "Opened \(doors)"
    }
}

final class CloseCommand: DoorCommand {
    let doors:String

    required init(doors: String) {
        self.doors = doors
    }
    
    func execute() -> String {
        return "Closed \(doors)"
    }
}

final class HAL9000DoorsOperations {
    let openCommand: DoorCommand
    let closeCommand: DoorCommand
    
    init(doors: String) {
        self.openCommand = OpenCommand(doors:doors)
        self.closeCommand = CloseCommand(doors:doors)
    }
    
    func close() -> String {
        return closeCommand.execute()
    }
    
    func open() -> String {
        return openCommand.execute()
    }
}Copy the code

usage

let podBayDoors = "Pod Bay Doors"
let doorModule = HAL9000DoorsOperations(doors:podBayDoors)

doorModule.open()
doorModule.close()Copy the code

🎶 Interpreter

Given a language, define a representation of its grammar and define an interpreter that uses that representation to interpret sentences in the language.

Example:

protocol IntegerExpression {
    func evaluate(_ context: IntegerContext) -> Int
    func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression
    func copied() -> IntegerExpression
}

final class IntegerContext {
    private var data: [Character:Int] = [:]

    func lookup(name: Character) -> Int {
        return self.data[name]!
    }

    func assign(expression: IntegerVariableExpression, value: Int) {
        self.data[expression.name] = value
    }
}

final class IntegerVariableExpression: IntegerExpression {
    let name: Character

    init(name: Character) {
        self.name = name
    }

    func evaluate(_ context: IntegerContext) -> Int {
        return context.lookup(name: self.name)
    }

    func replace(character name: Character, integerExpression: IntegerExpression) -> IntegerExpression {
        if name == self.name {
            return integerExpression.copied()
        } else {
            return IntegerVariableExpression(name: self.name)
        }
    }

    func copied() -> IntegerExpression {
        return IntegerVariableExpression(name: self.name)
    }
}

final class AddExpression: IntegerExpression {
    private var operand1: IntegerExpression
    private var operand2: IntegerExpression

    init(op1: IntegerExpression, op2: IntegerExpression) {
        self.operand1 = op1
        self.operand2 = op2
    }

    func evaluate(_ context: IntegerContext) -> Int {
        return self.operand1.evaluate(context) + self.operand2.evaluate(context)
    }

    func replace(character: Character, integerExpression: IntegerExpression) -> IntegerExpression {
        return AddExpression(op1: operand1.replace(character: character, integerExpression: integerExpression),
                             op2: operand2.replace(character: character, integerExpression: integerExpression))
    }

    func copied() -> IntegerExpression {
        return AddExpression(op1: self.operand1, op2: self.operand2)
    }
}Copy the code

usage

var context = IntegerContext()

var a = IntegerVariableExpression(name: "A")
var b = IntegerVariableExpression(name: "B")
var c = IntegerVariableExpression(name: "C")

var expression = AddExpression(op1: a, op2: AddExpression(op1: b, op2: c)) // a + (b + c)

context.assign(expression: a, value: 2)
context.assign(expression: b, value: 1)
context.assign(expression: c, value: 3)

var result = expression.evaluate(context)Copy the code

🍫 Iterator

The iterator pattern allows users to tour each element in a container through a specific interface without knowing the underlying implementation.

Example:

struct Novella {
    let name: String
}

struct Novellas {
    let novellas: [Novella]
}

struct NovellasIterator: IteratorProtocol {

    private var current = 0
    private let novellas: [Novella]

    init(novellas: [Novella]) {
        self.novellas = novellas
    }

    mutating func next() -> Novella? {
        defer { current += 1 }
        return novellas.count > current ? novellas[current] : nil
    }
}

extension Novellas: Sequence {
    func makeIterator() -> NovellasIterator {
        return NovellasIterator(novellas: novellas)
    }
}Copy the code

usage

let greatNovellas = Novellas(novellas: [Novella(name: "The Mist")] )

for novella in greatNovellas {
    print("I've read: \(novella)")
}Copy the code

💐 Mediators

Encapsulating a set of object interactions with a mediator object, the mediator loosens the coupling by allowing the objects to interact without explicitly, and can change their interactions independently.

Example:

protocol Receiver {
    associatedtype MessageType
    func receive(message: MessageType)
}

protocol Sender {
    associatedtype MessageType
    associatedtype ReceiverType: Receiver
    
    var recipients: [ReceiverType] { get }
    
    func send(message: MessageType)
}

struct Programmer: Receiver {
    let name: String
    
    init(name: String) {
        self.name = name
    }
    
    func receive(message: String) {
        print("\(name) received: \(message)")
    }
}

final class MessageMediator: Sender {
    internal var recipients: [Programmer] = []
    
    func add(recipient: Programmer) {
        recipients.append(recipient)
    }
    
    func send(message: String) {
        for recipient in recipients {
            recipient.receive(message: message)
        }
    }
}
Copy the code

usage

func spamMonster(message: String, worker: MessageMediator) {
    worker.send(message: message)
}

let messagesMediator = MessageMediator()

let user0 = Programmer(name: "Linus Torvalds")
let user1 = Programmer(name: "Avadis 'Avie' Tevanian")
messagesMediator.add(recipient: user0)
messagesMediator.add(recipient: user1)

spamMonster(message: "I'd Like to Add you to My Professional Network", worker: messagesMediator)
Copy the code

💾 Memento

Capture the internal state of an object and store the state outside of the object without breaking encapsulation. This will restore the object to its original saved state

Example:

typealias Memento = [String: String]Copy the code

Originator

protocol MementoConvertible { var memento: Memento { get } init? (memento: Memento) } struct GameState: MementoConvertible { private enum Keys { static let chapter = "com.valve.halflife.chapter" static let weapon = "com.valve.halflife.weapon" } var chapter: String var weapon: String init(chapter: String, weapon: String) { self.chapter = chapter self.weapon = weapon } init? (memento: Memento) { guard let mementoChapter = memento[Keys.chapter], let mementoWeapon = memento[Keys.weapon] else { return nil } chapter = mementoChapter weapon = mementoWeapon } var memento: Memento { return [ Keys.chapter: chapter, Keys.weapon: weapon ] } }Copy the code

Caretaker (Caretaker)

enum CheckPoint {

    private static let defaults = UserDefaults.standard

    static func save(_ state: MementoConvertible, saveName: String) {
        defaults.set(state.memento, forKey: saveName)
        defaults.synchronize()
    }

    static func restore(saveName: String) -> Any? {
        return defaults.object(forKey: saveName)
    }
}Copy the code

usage

var gameState = GameState(chapter: "Black Mesa Inbound", weapon: "Crowbar")

gameState.chapter = "Anomalous Materials"
gameState.weapon = "Glock 17"
CheckPoint.save(gameState, saveName: "gameState1")

gameState.chapter = "Unforeseen Consequences"
gameState.weapon = "MP5"
CheckPoint.save(gameState, saveName: "gameState2")

gameState.chapter = "Office Complex"
gameState.weapon = "Crossbow"
CheckPoint.save(gameState, saveName: "gameState3")

if let memento = CheckPoint.restore(saveName: "gameState1") as? Memento {
    let finalState = GameState(memento: memento)
    dump(finalState)
}Copy the code

👓 Observer

A target object manages all observer objects that depend on it and actively notifies itself when its state changes

Example:

protocol PropertyObserver : class { func willChange(propertyName: String, newPropertyValue: Any?) func didChange(propertyName: String, oldPropertyValue: Any?) } final class TestChambers { weak var observer:PropertyObserver? private let testChamberNumberName = "testChamberNumber" var testChamberNumber: Int = 0 { willSet(newValue) { observer? .willChange(propertyName: testChamberNumberName, newPropertyValue: newValue) } didSet { observer? .didChange(propertyName: testChamberNumberName, oldPropertyValue: oldValue) } } } final class Observer : PropertyObserver { func willChange(propertyName: String, newPropertyValue: Any?) { if newPropertyValue as? Int == 1 { print("Okay. Look. We both said a lot of things that you're going to regret.") } } func didChange(propertyName: String, oldPropertyValue: Any?) { if oldPropertyValue as? Int == 0 { print("Sorry about the mess. I've really let the place go since you killed me.") } } }Copy the code

usage

var observerInstance = Observer()
var testChambers = TestChambers()
testChambers.observer = observerInstance
testChambers.testChamberNumber += 1Copy the code

🐉 Status (State)

In state mode, the behavior of an object changes based on its internal state. This pattern allows a class object to change at run time.

Example:

final class Context { private var state: State = UnauthorizedState() var isAuthorized: Bool { get { return state.isAuthorized(context: self) } } var userId: String? { get { return state.userId(context: self) } } func changeStateToAuthorized(userId: String) { state = AuthorizedState(userId: userId) } func changeStateToUnauthorized() { state = UnauthorizedState() } } protocol State { func isAuthorized(context:  Context) -> Bool func userId(context: Context) -> String? } class UnauthorizedState: State { func isAuthorized(context: Context) -> Bool { return false } func userId(context: Context) -> String? { return nil } } class AuthorizedState: State { let userId: String init(userId: String) { self.userId = userId } func isAuthorized(context: Context) -> Bool { return true } func userId(context: Context) -> String? { return userId } }Copy the code

usage

let userContext = Context()
(userContext.isAuthorized, userContext.userId)
userContext.changeStateToAuthorized(userId: "admin")
(userContext.isAuthorized, userContext.userId) // now logged in as "admin"
userContext.changeStateToUnauthorized()
(userContext.isAuthorized, userContext.userId)Copy the code

💡 Strategy

Objects have a behavior, but different scenarios have different algorithms for implementing that behavior. Strategy mode:

  • Defines a family of algorithms (business rules);
  • Encapsulate each algorithm;
  • Algorithms of this family are interchangeable.

Example:

struct TestSubject { let pupilDiameter: Double let blushResponse: Double let isOrganic: Bool } protocol RealnessTesting: AnyObject { func testRealness(_ testSubject: TestSubject) -> Bool } final class VoightKampffTest: RealnessTesting { func testRealness(_ testSubject: TestSubject) - > Bool {return TestSubject. PupilDiameter < 30.0 | | TestSubject. BlushResponse = = 0.0}} final class GeneticTest: RealnessTesting { func testRealness(_ testSubject: TestSubject) -> Bool { return testSubject.isOrganic } } final class BladeRunner { private let strategy: RealnessTesting init(test: RealnessTesting) { self.strategy = test } func testIfAndroid(_ testSubject: TestSubject) -> Bool { return ! strategy.testRealness(testSubject) } }Copy the code

usage

Let Rachel = TestSubject(Flushing diameter: 30.2, blushResponse: 0.3, isOrganic: false) // Deckard is using a traditional test let deckard = BladeRunner(test: VoightKampffTest()) let isRachelAndroid = deckard.testIfAndroid(rachel) // Gaff is using a very precise method let gaff = BladeRunner(test: GeneticTest()) let isDeckardAndroid = gaff.testIfAndroid(rachel)Copy the code

🏃 Visitor

Encapsulates operations that operate on elements of a data structure and defines new operations that operate on those elements without changing the data structure.

Example:

protocol PlanetVisitor {
	func visit(planet: PlanetAlderaan)
	func visit(planet: PlanetCoruscant)
	func visit(planet: PlanetTatooine)
    func visit(planet: MoonJedha)
}

protocol Planet {
	func accept(visitor: PlanetVisitor)
}

final class MoonJedha: Planet {
    func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) }
}

final class PlanetAlderaan: Planet {
    func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) }
}

final class PlanetCoruscant: Planet {
	func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) }
}

final class PlanetTatooine: Planet {
	func accept(visitor: PlanetVisitor) { visitor.visit(planet: self) }
}

final class NameVisitor: PlanetVisitor {
	var name = ""

	func visit(planet: PlanetAlderaan)  { name = "Alderaan" }
	func visit(planet: PlanetCoruscant) { name = "Coruscant" }
	func visit(planet: PlanetTatooine)  { name = "Tatooine" }
    func visit(planet: MoonJedha)     	{ name = "Jedha" }
}
Copy the code

usage

let planets: [Planet] = [PlanetAlderaan(), PlanetCoruscant(), PlanetTatooine(), MoonJedha()]

let names = planets.map { (planet: Planet) -> String in
	let visitor = NameVisitor()
    planet.accept(visitor: visitor)

    return visitor.name
}

namesCopy the code

Creation pattern

The creation pattern is a design pattern that deals with object creation, trying to create objects in a way that suits the situation. Basic object creation can cause design problems or add complexity to your design. The creative pattern solves the problem by controlling the creation of objects in some way.

Source: Wikipedia

🌰 Abstract Factory

The abstract factory pattern provides a way to encapsulate a set of separate factories with the same topic. In normal use, a client program creates a concrete implementation of an abstract factory, and then uses the abstract factory as an interface to create concrete objects for that topic.

Example:

agreement

protocol BurgerDescribing { var ingredients: [String] { get } } struct CheeseBurger: BurgerDescribing { let ingredients: [String]} protocol making {func make() -> render render} BurgerMaking { func make() -> BurgerDescribing { return CheeseBurger(ingredients: ["Cheese", "Burger", "Lettuce", "Tomato"]) } } final class JackInTheBox: BurgerMaking { func make() -> BurgerDescribing { return CheeseBurger(ingredients: ["Cheese", "Burger", "Tomato", "Onions"]) } }Copy the code

The abstract factory

enum BurgerFactoryType: BurgerMaking {

    case bigKahuna
    case jackInTheBox

    func make() -> BurgerDescribing {
        switch self {
        case .bigKahuna:
            return BigKahunaBurger().make()
        case .jackInTheBox:
            return JackInTheBox().make()
        }
    }
}Copy the code

usage

let bigKahuna = BurgerFactoryType.bigKahuna.make()
let jackInTheBox = BurgerFactoryType.jackInTheBox.make()Copy the code

👷 Builder

An object construction pattern. It can abstract the construction process of complex objects (abstract classes), so that different implementation methods of this abstract process can construct objects with different manifestations (attributes).

Example:

final class DeathStarBuilder { var x: Double? var y: Double? var z: Double? typealias BuilderClosure = (DeathStarBuilder) -> () init(buildClosure: BuilderClosure) { buildClosure(self) } } struct DeathStar : CustomStringConvertible { let x: Double let y: Double let z: Double init? (builder: DeathStarBuilder) { if let x = builder.x, let y = builder.y, let z = builder.z { self.x = x self.y = y self.z = z } else { return nil } } var description:String { return "Death Star  at (x:\(x) y:\(y) z:\(z))" } }Copy the code

usage

Let empire = DeathStarBuilder {builder in builder. X = 0.1 builder. Y = 0.2 builder. Z = 0.3} let deathStar = DeathStar(builder:empire)Copy the code

🏭 Factory Method

Define an interface that creates an object, but let the class that implements the interface decide which class to instantiate. The factory method lets class instantiation be deferred to subclasses.

Example:

protocol CurrencyDescribing { var symbol: String { get } var code: String { get } } final class Euro: CurrencyDescribing {var symbol: String {return "€"} var code: String { return "EUR" } } final class UnitedStatesDolar: CurrencyDescribing { var symbol: String { return "$" } var code: String { return "USD" } } enum Country { case unitedStates case spain case uk case greece } enum CurrencyFactory { static func currency(for country: Country) -> CurrencyDescribing? { switch country { case .spain, .greece: return Euro() case .unitedStates: return UnitedStatesDolar() default: return nil } } }Copy the code

usage

let noCurrencyCode = "No Currency Code Available" CurrencyFactory.currency(for: .greece)? .code ?? noCurrencyCode CurrencyFactory.currency(for: .spain)? .code ?? noCurrencyCode CurrencyFactory.currency(for: .unitedStates)? .code ?? noCurrencyCode CurrencyFactory.currency(for: .uk)? .code ?? noCurrencyCodeCopy the code

🃏 Prototype

Return a new instance by “copying” an existing one, rather than creating a new one. The copied instance is what we call a “prototype,” which is customizable.

Example:

struct MoonWorker {

    let name: String
    var health: Int = 100

    init(name: String) {
        self.name = name
    }

    func clone() -> MoonWorker {
        return MoonWorker(name: name)
    }
}Copy the code

usage

let prototype = MoonWorker(name: "Sam Bell")

var bell1 = prototype.clone()
bell1.health = 12

var bell2 = prototype.clone()
bell2.health = 23

var bell3 = prototype.clone()
bell3.health = 0Copy the code

💍 Singleton

A singleton class must ensure that only one instance exists. Many times the whole system only needs to have one global object, which helps us coordinate the behavior of the whole system

Example:

final class ElonMusk {

    static let shared = ElonMusk()

    private init() {
        // Private initialization to ensure just one instance is created.
    }
}Copy the code

usage

let elon = ElonMusk.shared // There is only one Elon Musk folks.Copy the code

Structural mode

In software engineering, structural patterns are design patterns that simplify design by understanding the relationships between components in a consistent way.

Source: Wikipedia

🔌 Adapter

Adapter patterns are sometimes called wrapper styles or wrappers. Redirect the interface of a class to what the user expects. An adaptation enables classes that cannot work together because of incompatible interfaces to work together by wrapping the class’s own interface in an existing class.

Example:

protocol NewDeathStarSuperLaserAiming {
    var angleV: Double { get }
    var angleH: Double { get }
}Copy the code

By adaptation

struct OldDeathStarSuperlaserTarget {
    let angleHorizontal: Float
    let angleVertical: Float

    init(angleHorizontal: Float, angleVertical: Float) {
        self.angleHorizontal = angleHorizontal
        self.angleVertical = angleVertical
    }
}Copy the code

The adapter

struct NewDeathStarSuperlaserTarget: NewDeathStarSuperLaserAiming {

    private let target: OldDeathStarSuperlaserTarget

    var angleV: Double {
        return Double(target.angleVertical)
    }

    var angleH: Double {
        return Double(target.angleHorizontal)
    }

    init(_ target: OldDeathStarSuperlaserTarget) {
        self.target = target
    }
}Copy the code

usage

Let target = OldDeathStarSuperlaserTarget (angleHorizontal: 14.0, angleVertical: 12.0) the let newFormat = NewDeathStarSuperlaserTarget (target) newFormat. AngleH newFormat. AngleVCopy the code

🌉 Bridge

The bridge pattern separates the abstract parts from the implementation parts so that they can vary independently.

Example:

protocol Switch {
    var appliance: Appliance { get set }
    func turnOn()
}

protocol Appliance {
    func run()
}

final class RemoteControl: Switch {
    var appliance: Appliance

    func turnOn() {
        self.appliance.run()
    }
    
    init(appliance: Appliance) {
        self.appliance = appliance
    }
}

final class TV: Appliance {
    func run() {
        print("tv turned on");
    }
}

final class VacuumCleaner: Appliance {
    func run() {
        print("vacuum cleaner turned on")
    }
}Copy the code

usage

let tvRemoteControl = RemoteControl(appliance: TV())
tvRemoteControl.turnOn()

let fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner())
fancyVacuumCleanerRemoteControl.turnOn()Copy the code

🌿 Composite

Group objects into a tree structure to represent a partial-whole hierarchy. The composite pattern makes the use of single objects and composite objects consistent.

Example:

Component (Component)

protocol Shape {
    func draw(fillColor: String)
}Copy the code

Leaf nodes (Leafs)

final class Square: Shape {
    func draw(fillColor: String) {
        print("Drawing a Square with color \(fillColor)")
    }
}

final class Circle: Shape {
    func draw(fillColor: String) {
        print("Drawing a circle with color \(fillColor)")
    }
}
Copy the code

combination

final class Whiteboard: Shape {

    private lazy var shapes = [Shape]()

    init(_ shapes: Shape...) {
        self.shapes = shapes
    }

    func draw(fillColor: String) {
        for shape in self.shapes {
            shape.draw(fillColor: fillColor)
        }
    }
}Copy the code

usage

var whiteboard = Whiteboard(Circle(), Square())
whiteboard.draw(fillColor: "Red")Copy the code

🍧 Decorator

Decoration pattern is a design pattern that dynamically adds new behavior to a class in the field of object-oriented programming. In terms of functionality, decorated patterns are more flexible than subclassing, so you can add functionality to an object rather than the entire class.

Example:

protocol CostHaving { var cost: Double { get } } protocol IngredientsHaving { var ingredients: [String] { get } } typealias BeverageDataHaving = CostHaving & IngredientsHaving struct SimpleCoffee: BeverageDataHaving {let cost: Double = 1.0 let ingredients = ["Water", "Coffee"]} protocol BeverageHaving: BeverageDataHaving { var beverage: BeverageDataHaving { get } } struct Milk: BeverageHaving { let beverage: BeverageDataHaving var cost: Double {return beverage.cost + 0.5} var 2. [String] { return beverage.ingredients + ["Milk"] } } struct WhipCoffee: BeverageHaving { let beverage: BeverageDataHaving var cost: Double {return beverage.cost + 0.5} var 2. [String] { return beverage.ingredients + ["Whip"] } }Copy the code

usage

var someCoffee: BeverageDataHaving = SimpleCoffee()
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")
someCoffee = Milk(beverage: someCoffee)
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")
someCoffee = WhipCoffee(beverage: someCoffee)
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")Copy the code

🎁 Facade

The facade pattern provides a unified high-level interface for a set of interfaces in a subsystem, making the subsystem easier to use.

Example:

final class Defaults {

    private let defaults: UserDefaults

    init(defaults: UserDefaults = .standard) {
        self.defaults = defaults
    }

    subscript(key: String) -> String? {
        get {
            return defaults.string(forKey: key)
        }

        set {
            defaults.set(newValue, forKey: key)
        }
    }
}Copy the code

usage

Let storage = Defaults() // Store storage["Bishop"] = "Disconnect me. I'd rather be nothing"Copy the code

🍃 Flyweight

Use shared objects to minimize memory usage and share information with as many similar objects as possible; It is suitable for use when a large number of objects are simply repeated and thus unacceptably use large amounts of memory.

Example:

Struct SpecialityCoffee {let origin: String} protocol CoffeeSearching {func search(origin: String) -> SpecialityCoffee? } // Final class Menu: CoffeeSearching {private var coffeeAvailable: [String: SpecialityCoffee] = [:] func search(origin: String) -> SpecialityCoffee? { if coffeeAvailable.index(forKey: origin) == nil { coffeeAvailable[origin] = SpecialityCoffee(origin: origin) } return coffeeAvailable[origin] } } final class CoffeeShop { private var orders: [Int: SpecialityCoffee] = [:] private let menu: CoffeeSearching init(menu: CoffeeSearching) { self.menu = menu } func takeOrder(origin: String, table: Int) { orders[table] = menu.search(origin: origin) } func serve() { for (table, origin) in orders { print("Serving \(origin) to table \(table)") } } }Copy the code

usage

let coffeeShop = CoffeeShop(menu: Menu())

coffeeShop.takeOrder(origin: "Yirgacheffe, Ethiopia", table: 1)
coffeeShop.takeOrder(origin: "Buziraguhindwa, Burundi", table: 3)

coffeeShop.serve()Copy the code

☔ Protection Proxy

In proxy mode, a class is created to represent the functionality of another underlying class. A guard agent is used to restrict access.

Example:

protocol DoorOpening { func open(doors: String) -> String } final class HAL9000: DoorOpening { func open(doors: String) -> String { return ("HAL9000: Affirmative, Dave. I read you. Opened \(doors).") } } final class CurrentComputer: DoorOpening { private var computer: HAL9000! func authenticate(password: String) -> Bool { guard password == "pass" else { return false } computer = HAL9000() return true } func open(doors: String) -> String { guard computer ! = nil else { return "Access Denied. I'm afraid I can't do that." } return computer.open(doors: doors) } }Copy the code

usage

let computer = CurrentComputer()
let podBay = "Pod Bay Doors"

computer.open(doors: podBay)

computer.authenticate(password: "pass")
computer.open(doors: podBay)Copy the code

🍬 Virtual Proxy

In proxy mode, a class is created to represent the functionality of another underlying class. Virtual proxies are used for on-demand loading of objects.

Example:

protocol HEVSuitMedicalAid {
    func administerMorphine() -> String
}

final class HEVSuit: HEVSuitMedicalAid {
    func administerMorphine() -> String {
        return "Morphine administered."
    }
}

final class HEVSuitHumanInterface: HEVSuitMedicalAid {

    lazy private var physicalSuit: HEVSuit = HEVSuit()

    func administerMorphine() -> String {
        return physicalSuit.administerMorphine()
    }
}Copy the code

usage

let humanInterface = HEVSuitHumanInterface()
humanInterface.administerMorphine()Copy the code

Info

📖 Descriptions from: Gang of Four Design Patterns Reference Sheet