-
Notifications
You must be signed in to change notification settings - Fork 173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Week3 [Step2] som #100
Week3 [Step2] som #100
Conversation
CodeStarterCamp_Week3/Person.swift
Outdated
func isPayable(_ amount: Int) -> Bool { | ||
if walletInCash > amount { | ||
return false | ||
} else { | ||
return true | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분은 훨~씬 간단하게 코드를 고쳐볼 수 있습니다. ㅎㅎㅎ
단 한 줄로 줄일 수 있어요.
수식 부분의 결과가 true, 아니면 false 로 나오기 때문에, 그 수식 자체를 return 오른쪽에 붙여버리는 거에요.
그러면 그 판단 결과가 리턴값으로 바로 나오게 됩니다! 👍🏻
func isPayable(_ amount: Int) -> Bool { | |
if walletInCash > amount { | |
return false | |
} else { | |
return true | |
} | |
} | |
func isPayable(_ amount: Int) -> Bool { | |
return walletInCash >= amount | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bool 타입으로 반환 받으려고 하다 보니까 true
와 false
를 반환값으로 꼭 써야 하는 줄 알았어요.
'크거나 같은'의 의미를 갖는 비교 연산자
를 사용하면 되겠군요😮
CodeStarterCamp_Week3/Person.swift
Outdated
func spandCash (amount: Int) { | ||
if isPayable(amount) == false { | ||
print("잔돈이 부족합니다.") | ||
} else { | ||
walletInCash -= amount | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요 메서드는 일단 삭제할게요!
다른 메서드에서 간단하게 처리할 수 있을 것 같아요.
CodeStarterCamp_Week3/Person.swift
Outdated
var walletInCash: Int | ||
init(name: String, age: Int, habit: String? = nil, personalMBTI: String? = nil, walletInCash: Int) { | ||
init(name: String, age: Int, habit: String? = nil, MBTI: String? = nil, walletInCash: Int) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
프로퍼티들 ~ 이니셜라이저 ~ 메서드들
이렇게 각각의 종류들 사이에서는 공백 한 줄
넣어주시면 좋겠습니다!
가독성을 위해서요 ㅎㅎ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗! 공백 넣는 걸 계속 깜빡하는 거 같아요ㅠㅠ 수정했습니다!
CodeStarterCamp_Week3/Person.swift
Outdated
func buyCoffee(_ coffee: Coffee, at coffeeShop: CoffeeShop?) { | ||
if let cafe = coffeeShop { | ||
if let price = cafe.menu[coffee] { | ||
if walletInCash > price { | ||
walletInCash -= price | ||
print("\(coffee)를 구매하였습니다.") | ||
coffeeShop?.order(coffee, by: self) | ||
} else { | ||
print("잔액이 \(price - walletInCash)원 만큼 부족합니다.") | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
이 메서드는 내부에서 if-let 옵셔널 바인딩이 2번이나 중첩돼서 쓰이고 있고
심지어 그 안에 또 if문이 들어가있어요.
요약하자면,if문을 3번 중첩
했다고 볼 수 있어요. 🥲 중첩이 하나만 깊어져도 가독성이 떨어지기 때문에
이런 경우엔 if-let 이 아니라 →guard-let
옵셔널 바인딩을 활용해보면 좋겠어요. -
그리고 이 메서드에 CoffeeShop 타입을 파라미터로 받잖아요?
그렇기 때문에, 주문하기 전에 가게가 열었는지, 닫았는지를 판단하는 일과
주문하고 싶은 메뉴가 가게에 있는지, 없는지 판단하는 일도소비자의 몫
으로 돌려보죠. 😄
(현실에서도, 가게 문 닫았는지는 지도로 검색해서 알아내고, 메뉴가 있는지도 미리 확인해볼 수 있으니까요.) -
이때, CoffeeShop 파라미터를 굳이
옵셔널
로 받을 필요도 없어 보여요.
커피를 주문한다면, 반드시 카페는 있어야 겠죠. 옵셔널로 받지 않는 게 더 깔끔하고 당연해보입니다!
func buyCoffee(_ coffee: Coffee, at coffeeShop: CoffeeShop) {
guard coffeeShop.openingHours.isEmpty == false else {
print("가게가 아직 오픈하지 않았습니다.")
return
}
guard let price = coffeeShop.menu[coffee] else {
print("주문한 커피가 메뉴에 없습니다.")
return
}
if isPayable(price) {
walletInCash -= price // 금액 지불이 가능(true)할 때, 돈을 차감합니다.
coffeeShop.order(coffee, price: price, customerName: name) // 커피샵의 order 메서드에 돈과 소비자의 이름을 파라미터로 보내버립니다.
} else {
print("\(coffee) 를 주문하기엔 잔액이 \(price - walletInCash)원 부족합니다.")
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
guard문을 스위프트 언어 배우면서 처음 접하는 거라 아직 if문이 더 익숙한가봐요...
guard문이 확실히 코드가 간결해지긴 해요👍
그러면 스위프트 언어에서는 if문을 코드의 간결성 때문에 거의 안 쓰나요? 궁금해졌습니다! -
openingHours를 설정해둔 이유는 실제 카페 문 앞에 [open]/[close] 팻말을 걸어두잖아요.
그게 참 매력적이고, 꼭 넣어보고 싶은 설정이라 넣게 된 거예요!
즉, 팻말을 위해 만든 프로퍼티예요☺️
그 팻말 관리를 고객이 아닌 카페 측에서 하니까 Coffee 소스 파일에 넣어둔 것인데, 지금 보니 기존의 order()메서드에 넣는 게 어색해보이네요 ㅎㅎ...
이 프로퍼티는 제가 따로 빼서 다른 메서드로 활용해보겠습니다💪 -
저도 CoffeeShop 파라미터를 굳이 옵셔널로 가져오고 싶지 않았는데, 코드 수정을 거듭하면서 옆에 뜨는 오류문을 확인하며 만들다가 옵셔널로 가져오게 된 거 같아요.
그때 워낙 멘붕인 상태에서(🤣🤣🤣🤣) 프로그래밍 했기 때문에 정확한 원인은 기억이 나질 않네요...🥲
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ㅎㅎㅎ 답변 감사합니다.
guard문하고 if문 중에 하나만 쓸 필요는 없어요!
저는 솔직히 반-반 섞어 쓰는 거 같습니다.
둘의 늬앙스 차이가 좀 있기 때문에... 나중 가면 자연스럽게 선택하실 수 있게 될 거에요! 😄
일단 이번 코멘트에서 제가 if문 3중 중첩
을 제거하기 위해 guard문
을 2번 사용했는데요,
살펴 보시면, 주문(order)
이라는 행위를 하기 까지, 예외 케이스
를 먼저 걸러내주는 방식으로 guard문을 사용했어요.
guard문은 early-exit(빠른 종료)
목적으로 쓰이기 좋다는 걸 느껴보셨으면 합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
감사합니다:) 감이 오고 있는 거 같아요 ㅎㅎ!
var pickUpTable: Coffee? { | ||
didSet { | ||
if let coffee = pickUpTable { | ||
print("\(customerName)님, \(coffee)가 완성되어 픽업 테이블에 올라왔습니다.") | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
프로퍼티 옵저버 정말 잘 만드셨어요! 💯
var customerName: String = "" | ||
init(owner: String, openingHours: String, menu: [Coffee: Int] = [:], barista: Person?) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기서도 마찬가지로, 타입 내부의 프로퍼티들 ~ 이니셜라이저 ~ 메서드들은
각각 공백 한 줄
을 경계로 분리해주시면 더 좋겠습니다!
func showMenu() -> String { | ||
var menuDetail = "\(owner) 카페 메뉴판\n" | ||
if menu.isEmpty { | ||
return "현재 메뉴 준비 중입니다." | ||
} else { | ||
for (coffee, price) in menu { | ||
menuDetail += "|| \(coffee) - \(price)원 ||\n" | ||
} | ||
} | ||
return menuDetail | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 메서드는 진짜 재미나게 잘 만드셨는데, 실제로 호출되는 부분이 없어서 좀 아쉽더라구요!
편하게 호출할 수 있도록, 리턴값을 없애고 단순 print 출력만 해주는
메서드로 고쳐서
어떻게든 쓸 수 있게 만들어보죠. ㅎㅎㅎ
func showMenu() {
if menu.isEmpty {
print("현재 메뉴 준비 중입니다.")
} else {
print("☕️☕️☕️ \(owner) 카페 메뉴판 ☕️☕️☕️")
for (coffee, price) in menu {
print("|| \(coffee) - \(price)원 ||")
}
print("----------------------------") // 메뉴 출력 끝나고 경계선 그어주기!
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
☕️ 커피 이모지까지 있으니 정말 카페 메뉴판이 된 거 같아요!
생각해보니 막상 만들어 놓고 호출을 안 했네요🤣🤣🤣
func order(_ coffee: Coffee, by customer: Person) -> Coffee? { | ||
if openingHours.isEmpty { | ||
print("아직 오픈 시간이 아닙니다.") | ||
} else { | ||
if let price = menu[coffee] { | ||
if customer.isPayable(price) { | ||
print("\(customer.name)님의 \(coffee)가 주문 되었습니다.") | ||
self.customerName = customer.name | ||
coffeeShopProfit += price | ||
makeCoffee(coffee) | ||
return coffee | ||
} else { | ||
print("잔액이 \(price - customer.walletInCash)만큼 부족합니다.") | ||
} | ||
} | ||
} | ||
return coffee | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
먼저, 메서드의 리턴값을 없애도 괜찮을 것 같아요.
왜냐면, 내부에서 커피를 만들면,pickUpTable
에 바로 올려버리기 때문에, 리턴값이 쓰이지 않는다는 노란색⚠️ 경고도 뜨더라구요! -
그리고 메서드 파라미터들 구성을 바꿨어요.
굳이Person 타입
을 통째로 받지 않고, 손님이 건내는 돈과 손님의 이름을 받으면, price 를 여기서 또 옵셔널 바인딩할 필요가 사라져요!
그리고 블루보틀 같은 카페에서는, 주문할 때 카드 건내면서, 동시에손님의 이름
을 얘기해줘야 하잖아요?
그런 컨셉을 생각해봤어요! 😄 -
오픈 시간이나, isPayable 같은 로직은, 여기선 필요 없어요.
왜냐면 이미 소비자 측에서guard문
통해서 다 처리하고 넘어올 거니까, 여기서 괜히 또 해줄 필요가 없어졌어요.
func order(_ coffee: Coffee, price: Int, customerName: String) {
showMenu() // 이거 여기에 끼워넣었어요. ㅎㅎ
print("\(customerName) 님의 \(coffee) 주문이 들어왔습니다.")
self.customerName = customerName
coffeeShopProfit += price // 파라미터로 들어온 돈을, 가게의 매출에 더해줘요.
makeCoffee(menu: coffee) // 진짜로 커피를 만드는 메서드 호출
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드가 훨씬 간단해졌네요😮
파라미터로 진작 가져올 걸 그랬어요🥲
func makeCoffee(_ coffee: Coffee) { | ||
print("\(coffee)를 만드는 중입니다.") | ||
pickUpTable = coffee | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
메서드 이름부터 보면, 호출될 때
makeCoffee(coffee)
→ 이런 식으로, "커피" 단어가 2번 반복되기 때문에, 뒤에 커피가 뭘 의미하는 건지 부정확해보였어요.
그래서 메서드 파라미터를 생략하지 않고, Argument Labels로menu
를 끼워넣었어요! -
그리고 솜이 요청했던...
시간이 조금 걸리게 하는 방법
⏲️
간단하게 구현해봤어요.
참고로 여기서 사용한 Thread.sleep(forTimeInterval:) → 이 메서드는 아주 ☠️ 위험한 ☠️ 메서드입니다.
작업이 이루어지는 스레드를 잠들게 해서, 강제로 1초 멈춰버리는 겁니다.
이번 스텝은 화면(UI)도 없고, 손님도 1명이라 사용한 건데, 만약 화면이 있는 앱에서 Thread.sleep 걸어버리면, 슬립되는 동안에는 아예 화면이 멈춰버려서, 유저와 어떠한 interaction 도 할 수가 없게 됩니다. 😅
func makeCoffee(menu coffee: Coffee) {
// 여기에서 시간 4초 정도 부여하고, 1초 마다 과정을 출력해볼게요!
Thread.sleep(forTimeInterval: 1)
print("에스프레소 내리는 중...")
Thread.sleep(forTimeInterval: 1)
print("재료 섞는 중...")
Thread.sleep(forTimeInterval: 1)
print("포장 중...")
Thread.sleep(forTimeInterval: 1)
pickUpTable = coffee // 완성!
}
- 그러면 안전하게 시간 차를 부여하려면 어떻게 해야 할까요?
개념을 더 어렵게 만들면 이렇게도 될 수 있습니다.
바리스타 1명이 커피를 내리는 데 5초가 걸리고, 한 번에 한 커피 밖에 작업을 못 한다고 했을 때
바리스타가 2~3명으로 늘어나고, 손님이 10명이 몰려와서 막 주문을 집어넣는 다고 생각해보는 거죠...
이때 필요한 개념이 멀티스레딩과 GCD 인데요...!
이건 야곰 부트캠프에서도 중반부 돼서야 다루는 내용이고..
사실 저도 공부가 더 필요한 부분이라서, 이런 게 있구나 하고만 넘어가시면 좋겠어요! 🙏🏻
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 정말 참고용으로만 봐야겠네요...!
예전의 컴퓨터는 연산기능 밖에 없었는데, 세상의 모든 것을 컴퓨터 안에 담기 위해 객체지향 프로그램이 만들어졌다고 객체지향 프로그램 파트에서 배웠던 것이 기억나서
실제로 커피를 만드는 시간도 구현할 수 있지 않을까? 궁금해져서 질문을 드렸어요 ㅎㅎ
더 성장해서 앱을 만들게 될 때 쓸 수 있게 되겠네요! 알려주셔서 감사합니다
CodeStarterCamp_Week3/main.swift
Outdated
var yagombucks = CoffeeShop(owner: "야곰", openingHours: "10:00 ~ 20:00", menu: Coffee.menu, barista: misterLee) | ||
|
||
|
||
missKim.buyCoffee(Coffee.caramelMacchiato, at: yagombucks) | ||
missKim.walletInCash = 4000 | ||
missKim.buyCoffee(Coffee.caramelMacchiato, at: yagombucks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
야곰벅스 인스턴스는 굳이 var 로 만들 필요가 없어요!
항상 상수인 let
을 기본으로 생각하시고, 에러가 뜨거나 변경될 필요가 있는 경우만 var 로 선언해주세요. 😄
그리고 메뉴가 3가지나 있고, 돈이 부족한 경우에 예외 처리
까지 잘 구현해놨기 때문에
그런 것들을 테스트 하기 위해, 미스킴의 주문을 아래와 같이 변경해봤어요!
var yagombucks = CoffeeShop(owner: "야곰", openingHours: "10:00 ~ 20:00", menu: Coffee.menu, barista: misterLee) | |
missKim.buyCoffee(Coffee.caramelMacchiato, at: yagombucks) | |
missKim.walletInCash = 4000 | |
missKim.buyCoffee(Coffee.caramelMacchiato, at: yagombucks) | |
let yagombucks = CoffeeShop(owner: "야곰", openingHours: "10:00 ~ 20:00", menu: Coffee.menu, barista: misterLee) | |
missKim.buyCoffee(.caramelMacchiato, at: yagombucks) // 카라멜 마끼아또 시켜보고 | |
missKim.buyCoffee(.americano, at: yagombucks) // 아메리카노도 시켜보고 | |
missKim.buyCoffee(.caffeLatte, at: yagombucks) // 돈 부족한 경우도 테스트해보고 |
조금 아쉬운 상태에서 push를 하게 되었습니다. 캠프가 끝나면 꼭 저렇게 만들어보려고요:) |
func order(_ coffee: Coffee, price: Int, customerName: String) { | ||
openCafe() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
openCafe()
라는 메서드가 존재하지 않아서, 컴파일이 안 됩니다. 😢
커밋 찍기 전에 꼭 컴파일 성공 여부를 확인해주세요! 👍🏻
CodeStarterCamp_Week3/Person.swift
Outdated
func spandCash(amount: Int) { | ||
if isPayable(amount) == false { | ||
print("잔돈이 부족합니다.") | ||
} else { | ||
walletInCash -= amount | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 메서드는 구현은 됐지만, 호출되고 있지 않습니다.
그리고 삭제하더라도, 프로그램 실행에 전혀 문제가 없네요!
따라서, 삭제 커밋 해주시면 좋겠습니다! 😄
그리고 오타도 있네요. ㅎㅎㅎ spand → spend
func makeCoffee(menu coffee: Coffee) { | ||
pickUpTable = coffee | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 지난 코멘트에서 알려드린 Thread.sleep
사용해서, 커피가 만들어지는 데 시간을 부여해보셔도 좋아요!
위험한 메서드이지만, 사용해보라고 알려드렸던 거에요. 👍🏻
다음 커밋에 포함시켜보세요!! 😄
수정했습니다! 앞으로 컴파일 에러 여부 꼭 확인하고 push하겠습니다😅 |
정말 긴 과정이었네요! |
@Jager-yoo
Step2를 하면서 정말 머리가 많이 아팠습니다..
어제 예거에게 디엠 드렸던 것처럼, 다른 파일에 있는 객체를 인식하지 못 해서 일단 모든 파일들의 코드를 플레이그라운드에 복붙하면서 진행했었는데, 그럼에도 한계가 오더라고요. 잠시 파라미터를 잊었던 거 같아요. 그 문제는 해결해서 PR을 보내봅니다!
어려웠던 점
저는 원래 이렇게 생각을 했어요.
사람이 주문을 한다.
->바리스타가 주문을 받는다.
->바리스타가 커피를 만든다
->픽업테이블로 손님을 호출한다.
보통 우리가 카페에 가서 커피를 주문하고 받을 때의 방식이죠.
그래서
missKim.buyCoffee()
->barista.order()
->barista.makeCoffee()
이 순으로 main 파일에 호출할려니...coffee
프로퍼티는 잘 들어오지만cash
나Person.name
이런 프로퍼티들이 안 들어오기 시작하더라고요.그 때 인스턴스가 상호작용한다.. 그 의미가 뭔지 알겠더라고요. 순서도는 아니지만 메모장에 써둔 설계도(?)가 무의미해지는 순간이었어요😵💫
해보고 싶은 부분
보통 주문을 넣고 바로 커피가 완성되지는 않잖아요:)
만드는 시간이 필요할 거 같은데
주문하고 5분 뒤
라던가, 5분 정도 만드는 시간을 주고 싶어요.지금은 run을 하면 모든 메서드들이 바로 호출되지만 호출될 때, 시간 차를 만드는 방법은 없을까요?