Last active
August 1, 2023 10:08
-
-
Save mrbodich/81716523049d2633b61ff8e9f0673e2e to your computer and use it in GitHub Desktop.
Chain of Responsibility + Decorator + Single Responsibility — ATM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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