Skip to content

Instantly share code, notes, and snippets.

@mrbodich
Last active August 1, 2023 10:08
Show Gist options
  • Save mrbodich/81716523049d2633b61ff8e9f0673e2e to your computer and use it in GitHub Desktop.
Save mrbodich/81716523049d2633b61ff8e9f0673e2e to your computer and use it in GitHub Desktop.
Chain of Responsibility + Decorator + Single Responsibility — ATM
//MARK: - Withdrawing.swift
import Foundation
protocol Withdrawing {
func capacity(amount: Int) -> Int
}
extension Withdrawing {
func chained(withNext next: Withdrawing) -> Withdrawing {
WithdrawingDecorator(main: self, relief: next)
}
}
/// MARK: Located in separate file with the Withdrawing protocol to keep incapsulation
fileprivate struct WithdrawingDecorator: Withdrawing {
let main: Withdrawing
let relief: Withdrawing
func capacity(amount: Int) -> Int {
let mainCapacity = main.capacity(amount: amount)
let change = amount - mainCapacity
switch change {
case ..<0: fatalError("Unexpectedly withdrawed more than requested")
case 0: return amount
default: return mainCapacity + relief.capacity(amount: change)
}
}
}
//MARK: - ATM.swift
import Foundation
final class MoneyPile: Withdrawing {
private let value: Int
private let quantity: Int
init(value: Int, quantity: Int) {
self.value = value
self.quantity = quantity
}
func capacity(amount: Int) -> Int {
let fullCapacity = value * quantity
let desiredAmount = min(fullCapacity, amount)
let change = desiredAmount % value
return desiredAmount - change
}
}
let ten = MoneyPile(value: 10, quantity: 6)
let twenty = MoneyPile(value: 20, quantity: 2)
let fifty = MoneyPile(value: 50, quantity: 2)
let hundred = MoneyPile(value: 100, quantity: 1)
let atm: Withdrawing = hundred
.chained(withNext: fifty)
.chained(withNext: twenty)
.chained(withNext: ten)
for value in [373, 300, 295, 177, 160] {
let capacity = atm.capacity(amount: value)
switch capacity == value {
case true: print("✅ Success. You can withdraw \(value)")
case false: print("❌ Failed to withdraw \(value). You can withdraw \(capacity)")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment