diff --git a/Bank.swift b/Bank.swift index e90bfee7a..5de93d7ef 100644 --- a/Bank.swift +++ b/Bank.swift @@ -12,21 +12,15 @@ final class Bank { private var finishedClientCount = 0 private var businessTime: TimeInterval? - func operateBank(teller: Int, client: [Client]) { + func open(teller: [Teller], client: [Client]) { let openTime = Date() - initTellers(teller) + tellers = teller clients = client.sorted() assignBusinessToTeller() businessTime = Date().timeIntervalSince(openTime) Dashboard.printCloseMessage(finishedClientCount, businessTime) - closeBank() - } - - private func initTellers(_ count: Int) { - for windowNumber in 1...count { - tellers.append(Teller(windowNumber: windowNumber)) - } + resetFinishedClientCount() } private func assignBusinessToTeller() { @@ -34,24 +28,22 @@ final class Bank { var isContinue = true while isContinue { - for teller in self.tellers { - if self.clients.count == 0 { + for teller in tellers { + if clients.count == 0 { isContinue = false break } if teller.isNotWorking { let client = clients.removeFirst() teller.handleBusiness(for: client, withDispatchGroup: dispatchGroup) - self.finishedClientCount += 1 + finishedClientCount += 1 } } } dispatchGroup.wait() } - private func closeBank() { - tellers.removeAll() - clients.removeAll() + private func resetFinishedClientCount() { finishedClientCount = 0 } } diff --git a/BankManagerConsoleApp/BankManagerConsoleApp.xcodeproj/project.pbxproj b/BankManagerConsoleApp/BankManagerConsoleApp.xcodeproj/project.pbxproj index 0eb09925f..a088ffc3d 100644 --- a/BankManagerConsoleApp/BankManagerConsoleApp.xcodeproj/project.pbxproj +++ b/BankManagerConsoleApp/BankManagerConsoleApp.xcodeproj/project.pbxproj @@ -7,10 +7,16 @@ objects = { /* Begin PBXBuildFile section */ + 4C4D3B9325ADE7320070DB26 /* Clients.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4D3B9225ADE7320070DB26 /* Clients.swift */; }; + 4C4D3B9725ADE78D0070DB26 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4D3B9625ADE78D0070DB26 /* Menu.swift */; }; + 4C4D3B9B25ADE7A90070DB26 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4D3B9A25ADE7A90070DB26 /* Message.swift */; }; + 4C4D3B9F25ADE7BC0070DB26 /* BusinessType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4D3B9E25ADE7BC0070DB26 /* BusinessType.swift */; }; + 4C529BAA25ADF6FC00F287A8 /* Tellers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C529BA925ADF6FC00F287A8 /* Tellers.swift */; }; + 4CB8E9BB25A998E300C021F6 /* HeadOffice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8E9BA25A998E300C021F6 /* HeadOffice.swift */; }; 4CB8E9C425A99CE000C021F6 /* Dashboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB8E9C325A99CE000C021F6 /* Dashboard.swift */; }; 4CDDB11825A422B700EDC9CE /* Teller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDDB11725A422B700EDC9CE /* Teller.swift */; }; 4CDDB11B25A422CD00EDC9CE /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDDB11A25A422CD00EDC9CE /* Client.swift */; }; - 4CDDB11E25A422EF00EDC9CE /* Enum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDDB11D25A422EF00EDC9CE /* Enum.swift */; }; + 4CDDB11E25A422EF00EDC9CE /* StringFormattingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDDB11D25A422EF00EDC9CE /* StringFormattingError.swift */; }; C7694E7A259C3EC00053667F /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7694E79259C3EC00053667F /* main.swift */; }; C7D65D1B259C8190005510E0 /* Bank.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D65D1A259C8190005510E0 /* Bank.swift */; }; /* End PBXBuildFile section */ @@ -28,10 +34,16 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 4C4D3B9225ADE7320070DB26 /* Clients.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clients.swift; sourceTree = ""; }; + 4C4D3B9625ADE78D0070DB26 /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = ""; }; + 4C4D3B9A25ADE7A90070DB26 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; + 4C4D3B9E25ADE7BC0070DB26 /* BusinessType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BusinessType.swift; sourceTree = ""; }; + 4C529BA925ADF6FC00F287A8 /* Tellers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tellers.swift; sourceTree = ""; }; + 4CB8E9BA25A998E300C021F6 /* HeadOffice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadOffice.swift; sourceTree = ""; }; 4CB8E9C325A99CE000C021F6 /* Dashboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dashboard.swift; sourceTree = ""; }; 4CDDB11725A422B700EDC9CE /* Teller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Teller.swift; sourceTree = ""; }; 4CDDB11A25A422CD00EDC9CE /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; - 4CDDB11D25A422EF00EDC9CE /* Enum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Enum.swift; sourceTree = ""; }; + 4CDDB11D25A422EF00EDC9CE /* StringFormattingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringFormattingError.swift; sourceTree = ""; }; C7694E76259C3EC00053667F /* BankManagerConsoleApp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BankManagerConsoleApp; sourceTree = BUILT_PRODUCTS_DIR; }; C7694E79259C3EC00053667F /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; C7D65D1A259C8190005510E0 /* Bank.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bank.swift; path = ../../Bank.swift; sourceTree = ""; }; @@ -48,6 +60,17 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 4C4D3BA325ADE7D70070DB26 /* Enum */ = { + isa = PBXGroup; + children = ( + 4C4D3B9625ADE78D0070DB26 /* Menu.swift */, + 4C4D3B9A25ADE7A90070DB26 /* Message.swift */, + 4C4D3B9E25ADE7BC0070DB26 /* BusinessType.swift */, + 4CDDB11D25A422EF00EDC9CE /* StringFormattingError.swift */, + ); + path = Enum; + sourceTree = ""; + }; C7694E6D259C3EC00053667F = { isa = PBXGroup; children = ( @@ -67,11 +90,14 @@ C7694E78259C3EC00053667F /* BankManagerConsoleApp */ = { isa = PBXGroup; children = ( + 4C4D3BA325ADE7D70070DB26 /* Enum */, + 4CB8E9BA25A998E300C021F6 /* HeadOffice.swift */, 4CB8E9C325A99CE000C021F6 /* Dashboard.swift */, C7D65D1A259C8190005510E0 /* Bank.swift */, 4CDDB11725A422B700EDC9CE /* Teller.swift */, + 4C529BA925ADF6FC00F287A8 /* Tellers.swift */, 4CDDB11A25A422CD00EDC9CE /* Client.swift */, - 4CDDB11D25A422EF00EDC9CE /* Enum.swift */, + 4C4D3B9225ADE7320070DB26 /* Clients.swift */, C7694E79259C3EC00053667F /* main.swift */, ); path = BankManagerConsoleApp; @@ -135,11 +161,17 @@ buildActionMask = 2147483647; files = ( C7694E7A259C3EC00053667F /* main.swift in Sources */, + 4CB8E9BB25A998E300C021F6 /* HeadOffice.swift in Sources */, + 4C4D3B9325ADE7320070DB26 /* Clients.swift in Sources */, C7D65D1B259C8190005510E0 /* Bank.swift in Sources */, - 4CDDB11E25A422EF00EDC9CE /* Enum.swift in Sources */, + 4CDDB11E25A422EF00EDC9CE /* StringFormattingError.swift in Sources */, 4CDDB11B25A422CD00EDC9CE /* Client.swift in Sources */, + 4C4D3B9725ADE78D0070DB26 /* Menu.swift in Sources */, + 4C4D3B9B25ADE7A90070DB26 /* Message.swift in Sources */, 4CB8E9C425A99CE000C021F6 /* Dashboard.swift in Sources */, 4CDDB11825A422B700EDC9CE /* Teller.swift in Sources */, + 4C4D3B9F25ADE7BC0070DB26 /* BusinessType.swift in Sources */, + 4C529BAA25ADF6FC00F287A8 /* Tellers.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Client.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Client.swift index 19020ec62..d44e49418 100644 --- a/BankManagerConsoleApp/BankManagerConsoleApp/Client.swift +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Client.swift @@ -7,19 +7,6 @@ import Foundation -struct Clients { - var list: [Client] = [] - - init(count: Int) { - for waitingNumber in 1...count { - guard let businessType = BusinessType.allCases.randomElement(), let priority = Client.Priority.allCases.randomElement() else { - return - } - list.append(Client(waitingNumber: waitingNumber, businessType: businessType, priority: priority)) - } - } -} - struct Client { enum Priority: Comparable, CaseIterable, CustomStringConvertible { case VVIP diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Clients.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Clients.swift new file mode 100644 index 000000000..b7dc86d65 --- /dev/null +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Clients.swift @@ -0,0 +1,22 @@ +// +// Clients.swift +// BankManagerConsoleApp +// +// Created by 리나 on 2021/01/12. +// + +import Foundation + +struct Clients { + var list: [Client] = [] + + init(count: Int) { + for waitingNumber in 1...count { + guard let businessType = BusinessType.allCases.randomElement(), let priority = Client.Priority.allCases.randomElement() else { + return + } + let clinet = Client(waitingNumber: waitingNumber, businessType: businessType, priority: priority) + list.append(clinet) + } + } +} diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Dashboard.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Dashboard.swift index 694b5f503..307aa2ae1 100644 --- a/BankManagerConsoleApp/BankManagerConsoleApp/Dashboard.swift +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Dashboard.swift @@ -19,7 +19,7 @@ struct Dashboard { static func printCloseMessage(_ count: Int, _ time: TimeInterval?) { guard let time = time else { - print("\(BankError.unknown)") + print("\(StringFormattingError.unknown)") return } let message = String(format: Message.close, count, time) diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Enum.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Enum.swift deleted file mode 100644 index 1bc12495b..000000000 --- a/BankManagerConsoleApp/BankManagerConsoleApp/Enum.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// String.swift -// BankManagerConsoleApp -// -// Created by 임리나 on 2021/01/05. -// - -import Foundation - -enum Menu: String { - case start = "1" - case end = "2" - - static let description = """ - 1: 은행 개점 - 2: 종료 - 입력 : - """ -} - -enum Message { - static let close = "업무가 마감되었습니다. 오늘 업무를 처리한 고객은 총 %d명이며, 총 업무시간은 %.2f초입니다." - static let tellerStart = "%d번 %@고객 %@업무 시작" - static let tellerFinish = "%d번 %@고객 %@업무 완료" -} - -enum BusinessType: CaseIterable, CustomStringConvertible { - case deposit - case loan - - var neededTime: TimeInterval { - switch self { - case .deposit: - return 0.7 - case .loan: - return 1.1 - } - } - - var description: String { - switch self { - case .deposit: - return "예금" - case .loan: - return "대출" - } - } -} - -enum BankError: Error, CustomStringConvertible { - case wrongInput - case unknown - - var description: String { - switch self { - case .wrongInput: - return "잘못된 입력입니다. 다시 입력해주세요" - case .unknown: - return "알 수 없는 에러가 발생했습니다." - } - } -} diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Enum/BusinessType.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Enum/BusinessType.swift new file mode 100644 index 000000000..ae71dd86d --- /dev/null +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Enum/BusinessType.swift @@ -0,0 +1,31 @@ +// +// BusinessType.swift +// BankManagerConsoleApp +// +// Created by 리나 on 2021/01/12. +// + +import Foundation + +enum BusinessType: CaseIterable, CustomStringConvertible { + case deposit + case loan + + var neededTime: TimeInterval { + switch self { + case .deposit: + return 0.7 + case .loan: + return 0.3 + } + } + + var description: String { + switch self { + case .deposit: + return "예금" + case .loan: + return "대출" + } + } +} diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Enum/Menu.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Enum/Menu.swift new file mode 100644 index 000000000..abfdaec7e --- /dev/null +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Enum/Menu.swift @@ -0,0 +1,19 @@ +// +// Menu.swift +// BankManagerConsoleApp +// +// Created by 리나 on 2021/01/12. +// + +import Foundation + +enum Menu: String { + case start = "1" + case end = "2" + + static let description = """ + 1: 은행 개점 + 2: 종료 + 입력 : + """ +} diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Enum/Message.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Enum/Message.swift new file mode 100644 index 000000000..25fd8e812 --- /dev/null +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Enum/Message.swift @@ -0,0 +1,16 @@ +// +// Message.swift +// BankManagerConsoleApp +// +// Created by 리나 on 2021/01/12. +// + +import Foundation + +enum Message { + static let close = "업무가 마감되었습니다. 오늘 업무를 처리한 고객은 총 %d명이며, 총 업무시간은 %.2f초입니다." + static let tellerStart = "%d번 %@고객 %@업무 시작" + static let tellerFinish = "%d번 %@고객 %@업무 완료" + static let loanStart = "%d번 %@고객 %@심사 시작" + static let loanFinish = "%d번 %@고객 %@심사 완료" +} diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Enum/StringFormattingError.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Enum/StringFormattingError.swift new file mode 100644 index 000000000..0d73acb1a --- /dev/null +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Enum/StringFormattingError.swift @@ -0,0 +1,24 @@ +// +// String.swift +// BankManagerConsoleApp +// +// Created by 임리나 on 2021/01/05. +// + +import Foundation + + + +enum StringFormattingError: Error, CustomStringConvertible { + case wrongInput + case unknown + + var description: String { + switch self { + case .wrongInput: + return "잘못된 입력입니다. 다시 입력해주세요" + case .unknown: + return "알 수 없는 에러가 발생했습니다." + } + } +} diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/HeadOffice.swift b/BankManagerConsoleApp/BankManagerConsoleApp/HeadOffice.swift new file mode 100644 index 000000000..33a801d68 --- /dev/null +++ b/BankManagerConsoleApp/BankManagerConsoleApp/HeadOffice.swift @@ -0,0 +1,22 @@ +// +// HeadOffice.swift +// BankManagerConsoleApp +// +// Created by 임리나 on 2021/01/09. +// + +import Foundation + +final class HeadOffice { + static let shared = HeadOffice() + private let neededTimeToJudgeLoan: TimeInterval = 0.5 + let loanQueue: DispatchQueue = DispatchQueue(label: "HeadOffice") + + private init() {} + + func judgeLoan(for client: Client) { + Dashboard.printStatus(for: client, about: Message.loanStart) + Thread.sleep(forTimeInterval: self.neededTimeToJudgeLoan) + Dashboard.printStatus(for: client, about: Message.loanFinish) + } +} diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Teller.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Teller.swift index f63af846d..0bf121949 100644 --- a/BankManagerConsoleApp/BankManagerConsoleApp/Teller.swift +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Teller.swift @@ -9,7 +9,7 @@ import Foundation final class Teller { private var windowNumber: Int - var workingQueue: DispatchQueue + let workingQueue: DispatchQueue private var isWorking: Bool = false var isNotWorking: Bool { return !isWorking @@ -24,10 +24,46 @@ final class Teller { isWorking = true workingQueue.async(group: group) { - Dashboard.printStatus(for: client, about: Message.tellerStart) - Thread.sleep(forTimeInterval: client.businessType.neededTime) - Dashboard.printStatus(for: client, about: Message.tellerFinish) + switch client.businessType { + case .deposit: + self.handleDeposit(for: client) + case .loan: + self.handleLoan(for: client) + } self.isWorking = false } } + + private func handleDeposit(for client: Client) { + Dashboard.printStatus(for: client, about: Message.tellerStart) + Thread.sleep(forTimeInterval: client.businessType.neededTime) + Dashboard.printStatus(for: client, about: Message.tellerFinish) + } + + + private func handleLoan(for client: Client) { + reviewDocument(for: client) + sendDocumentToHeadOffice(for: client) + finishLoan(for: client) + } + + private func reviewDocument(for client: Client) { + Dashboard.printStatus(for: client, about: Message.tellerStart) + Thread.sleep(forTimeInterval: client.businessType.neededTime) + } + + private func sendDocumentToHeadOffice(for client: Client) { + let semaphore = DispatchSemaphore(value: 0) + + HeadOffice.shared.loanQueue.async { + HeadOffice.shared.judgeLoan(for: client) + semaphore.signal() + } + semaphore.wait() + } + + private func finishLoan(for client: Client) { + Thread.sleep(forTimeInterval: client.businessType.neededTime) + Dashboard.printStatus(for: client, about: Message.tellerFinish) + } } diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/Tellers.swift b/BankManagerConsoleApp/BankManagerConsoleApp/Tellers.swift new file mode 100644 index 000000000..cfb796178 --- /dev/null +++ b/BankManagerConsoleApp/BankManagerConsoleApp/Tellers.swift @@ -0,0 +1,18 @@ +// +// Tellers.swift +// BankManagerConsoleApp +// +// Created by 리나 on 2021/01/13. +// + +import Foundation + +struct Tellers { + var list: [Teller] = [] + + init(count: Int) { + for windowNumber in 1...count { + list.append(Teller(windowNumber: windowNumber)) + } + } +} diff --git a/BankManagerConsoleApp/BankManagerConsoleApp/main.swift b/BankManagerConsoleApp/BankManagerConsoleApp/main.swift index 16258eaed..817444848 100644 --- a/BankManagerConsoleApp/BankManagerConsoleApp/main.swift +++ b/BankManagerConsoleApp/BankManagerConsoleApp/main.swift @@ -8,7 +8,7 @@ import Foundation func main() { let bank = Bank() - let tellerCount = 3 + let tellers = Tellers(count: 3) let maxClientCount = 30 let minClientCount = 10 var isContinue = true @@ -17,15 +17,15 @@ func main() { Dashboard.printMenu() guard let input = readLine(), let command = Menu(rawValue: input) else { - print("\(BankError.wrongInput)") + print("\(StringFormattingError.wrongInput)") continue } switch command { case .start: let randomNumber = Int.random(in: minClientCount...maxClientCount) - let clients = Clients.init(count: randomNumber) - bank.operateBank(teller: tellerCount, client: clients.list) + let clients = Clients(count: randomNumber) + bank.open(teller: tellers.list, client: clients.list) case .end: isContinue = false }