-
Notifications
You must be signed in to change notification settings - Fork 0
6기 실전 연습 #1
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
base: main
Are you sure you want to change the base?
6기 실전 연습 #1
Changes from all commits
7f3736c
33ed3b7
02ee06a
ae594f1
84d7e1a
fdcb515
899d1d7
bb15c6c
6a00c1d
db53b0b
ada3619
4118e7e
76a5871
a3fb630
f971da5
c39255f
eba78bd
0153122
2947c29
c9aac70
78120ef
138dccb
2b63914
d8afe91
9e26daf
82e958f
c491080
84eb7b0
516fe0e
6839720
b9d7c80
e579149
3120c7d
59326a6
bb17a9d
99d287f
de57b3d
6b57687
1b857c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
### 기능 목록 정리 | ||
|
||
- [x] 메뉴 추천을 받을 코치의 이름을 입력받는다. | ||
- [x] 코치의 이름은 최소 2글자, 최대 4글자이다. | ||
- [x] 코치는 최소 2명, 최대 5명까지 식사를 함께한다. | ||
- [x] 코치의 이름은 중복될 수 없다. | ||
- [x] 코치의 이름은 빈 값일 수 없다. | ||
- [x] 카테고리와 메뉴를 초기화한다. | ||
- [x] 각 코치가 못 먹는 메뉴를 입력받는다. | ||
- [x] 각 코치는 최소 0개, 최대 2개의 못 먹는 메뉴가 있다. | ||
- [x] 먹지 못하는 메뉴가 없으면 빈 값을 입력한다. | ||
- [x] 존재하지 않는 메뉴 입력시 에러처리한다. | ||
- [x] 각 메뉴는 중복될 수 없다. | ||
- [x] 메뉴를 추천해준다. | ||
- [x] 각 요일에 추천할 카테고리를 무작위로 정한다. | ||
- [x] 각 코치가 해당 요일에 먹을 메뉴를 추천한다. | ||
- [x] 월~금에 대해 해당 내용을 반복한다. | ||
- [x] 한 주에 같은 카테고리는 최대 2회까지만 고를 수 있다. | ||
- [x] 각 코치에게 한 주에 중복되지 않는 메뉴를 추천해야한다. | ||
- [x] 각 코치가 먹지 못하는 메뉴는 추천해주지 않는다. | ||
- [x] 추천 메뉴를 출력한다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,14 @@ | ||
package menu; | ||
|
||
import menu.controller.MenuController; | ||
import menu.domain.Recommender; | ||
|
||
public class Application { | ||
|
||
public static void main(String[] args) { | ||
// TODO: 프로그램 구현 | ||
MenuController menuController = new MenuController(InitialMenu.initMap(), | ||
new Recommender()); | ||
menuController.start(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package menu; | ||
|
||
import static menu.domain.Category.*; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import menu.domain.Category; | ||
|
||
public class InitialMenu { | ||
|
||
private InitialMenu() { | ||
} | ||
|
||
public static Map<Category, String> initMap() { | ||
Map<Category, String> menuMap = new HashMap<>(); | ||
menuMap.put(JAPAN, "규동, 우동, 미소시루, 스시, 가츠동, 오니기리, 하이라이스, 라멘, 오코노미야끼"); | ||
menuMap.put(KOREAN, "김밥, 김치찌개, 쌈밥, 된장찌개, 비빔밥, 칼국수, 불고기, 떡볶이, 제육볶음"); | ||
menuMap.put(CHINA, "깐풍기, 볶음면, 동파육, 짜장면, 짬뽕, 마파두부, 탕수육, 토마토 달걀볶음, 고추잡채"); | ||
menuMap.put(ASIAN, "팟타이, 카오 팟, 나시고렝, 파인애플 볶음밥, 쌀국수, 똠얌꿍, 반미, 월남쌈, 분짜"); | ||
menuMap.put(WESTERN, "라자냐, 그라탱, 뇨끼, 끼슈, 프렌치 토스트, 바게트, 스파게티, 피자, 파니니"); | ||
return menuMap; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package menu.controller; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Supplier; | ||
import java.util.stream.Collectors; | ||
import menu.domain.Category; | ||
import menu.domain.Coach; | ||
import menu.domain.Date; | ||
import menu.domain.Menu; | ||
import menu.domain.Recommender; | ||
import menu.view.InputView; | ||
import menu.view.OutputView; | ||
|
||
public class MenuController { | ||
|
||
private final Map<Category, String> menuMap; | ||
private final Recommender recommender; | ||
|
||
public MenuController(Map<Category, String> menuMap, Recommender recommender) { | ||
this.menuMap = menuMap; | ||
this.recommender = recommender; | ||
} | ||
|
||
public void start() { | ||
OutputView.printStart(); | ||
List<Coach> coaches = repeat(this::inputCoachName); | ||
inputCoachCanNotEatMenu(coaches); | ||
List<Category> categories = recommendMenu(coaches); | ||
OutputView.printRecommendResult(categories, coaches); | ||
} | ||
|
||
public List<Category> recommendMenu(List<Coach> coaches) { | ||
List<Category> categories = new ArrayList<>(); | ||
for (Date date : Date.values()) { | ||
Category category = recommender.pickOneCategory(categories); | ||
for (Coach coach : coaches) { | ||
Menu menu = recommender.recommendMenuForCoach(menuMap, category, coach); | ||
coach.addCanEatMenu(menu); | ||
} | ||
categories.add(category); | ||
} | ||
return categories; | ||
} | ||
|
||
private List<Coach> inputCoachName() { | ||
OutputView.inputCoachName(); | ||
List<String> coachNames = splitInput(InputView.readCoachName()); | ||
return coachNames.stream() | ||
.map(Coach::new) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
private List<Menu> inputCanNotEatMenu(Coach coach) { | ||
OutputView.inputMenu(coach); | ||
List<String> menus = splitInput(InputView.readMenus()); | ||
return menus.stream() | ||
.map(Menu::of) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
private void inputCoachCanNotEatMenu(List<Coach> coaches) { | ||
for (Coach coach : coaches) { | ||
List<Menu> menus = repeat(() -> inputCanNotEatMenu(coach)); | ||
if (menus != null) { | ||
coach.addCanNotEatMenu(menus); | ||
} | ||
} | ||
} | ||
Comment on lines
+64
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. repeat의 파라미터가 Supplier 형식이라 어떻게 파라미터 있는 메서드를 재입력 로직을 적용할 수 있을까 고민했는데 |
||
|
||
private List<String> splitInput(String input) { | ||
return Arrays.stream(input.split(",")) | ||
.collect(Collectors.toUnmodifiableList()); | ||
} | ||
|
||
private <T> T repeat(Supplier<T> inputReader) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제내릭을 사용하신게 인상깊네요! 덕분에 제내릭에 대해 한 번 알아볼 수 있는 경험이 되었습니다! |
||
try { | ||
return inputReader.get(); | ||
} catch (IllegalArgumentException e) { | ||
OutputView.printError(e); | ||
return repeat(inputReader); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package menu.domain; | ||
|
||
import java.util.Arrays; | ||
|
||
public enum Category { | ||
JAPAN(1, "일식"), | ||
KOREAN(2, "한식"), | ||
CHINA(3, "중식"), | ||
ASIAN(4, "아시안"), | ||
WESTERN(5, "양식"); | ||
|
||
private final int value; | ||
private final String type; | ||
|
||
Category(int value, String type) { | ||
this.value = value; | ||
this.type = type; | ||
} | ||
|
||
public static Category valueOf(int number) { | ||
return Arrays.stream(Category.values()) | ||
.filter(category -> category.getValue() == number) | ||
.findFirst() | ||
.orElseThrow(() -> new IllegalArgumentException("[ERROR] 유효하지 않은 값 입니다.")); | ||
} | ||
|
||
public int getValue() { | ||
return value; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return type; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package menu.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
public class Coach { | ||
|
||
private static final int COACH_NAME_MIN_SIZE = 2; | ||
private static final int COACH_NAME_MAX_SIZE = 4; | ||
|
||
private final String name; | ||
private final List<Menu> canNotEat = new ArrayList<>(); | ||
private final List<Menu> canEat = new ArrayList<>(); | ||
|
||
public Coach(String name) { | ||
validateCoachNameSize(name); | ||
this.name = name; | ||
} | ||
|
||
public void addCanNotEatMenu(List<Menu> menus) { | ||
canNotEat.addAll(menus); | ||
} | ||
|
||
public void addCanEatMenu(Menu menu) { | ||
canEat.add(menu); | ||
} | ||
|
||
public boolean canNotEatMenu(Menu menu) { | ||
return canNotEat.contains(menu); | ||
} | ||
|
||
public boolean isAlreadyRecommended(Menu menu) { | ||
return canEat.contains(menu); | ||
} | ||
|
||
private void validateCoachNameSize(String name) { | ||
if (name.length() < COACH_NAME_MIN_SIZE || name.length() > COACH_NAME_MAX_SIZE) { | ||
throw new IllegalArgumentException("[ERROR] 코치의 이름은 최소 2글자, 최대 4글자 입니다."); | ||
} | ||
} | ||
|
||
public List<Menu> getCanEat() { | ||
return canEat; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
Coach coach = (Coach) o; | ||
return Objects.equals(name, coach.name); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(name); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return name; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package menu.domain; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public enum Date { | ||
MON("월요일"), | ||
TUE("화요일"), | ||
WED("수요일"), | ||
THI("목요일"), | ||
FRI("금요일"); | ||
|
||
private final String date; | ||
|
||
Date(String date) { | ||
this.date = date; | ||
} | ||
|
||
public static List<String> getDateOfWeek() { | ||
return Arrays.stream(Date.values()) | ||
.map(Date::getDate) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
public String getDate() { | ||
return date; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package menu.domain; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
public class Menu { | ||
|
||
private final String menu; | ||
|
||
private Menu(String menu) { | ||
this.menu = menu; | ||
} | ||
|
||
public static Menu of(String menu) { | ||
return new Menu(menu); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. 한번 정적 팩토리 메서드 연습겸 사용해봤습니다 ㅋㅋㅋㅋ 이유는 없습니다. 그냥 생성자 사용해도 될 거 같네요!! |
||
|
||
public static Menu findMenuByName(List<String> menus, String menuName) { | ||
List<Menu> totalMenu = toMenu(menus); | ||
return totalMenu.stream() | ||
.filter(menu -> menu.checkMenuName(menuName)).findAny() | ||
.orElseThrow(() -> new IllegalArgumentException("[ERROR] 음식이 존재하지 않습니다.")); | ||
} | ||
|
||
private static List<Menu> toMenu(List<String> menus) { | ||
return menus.stream().map(Menu::of).collect(Collectors.toList()); | ||
} | ||
|
||
private boolean checkMenuName(String menuName) { | ||
return this.menu.equals(menuName); | ||
} | ||
|
||
public String getMenu() { | ||
return menu; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
Menu menu1 = (Menu) o; | ||
return Objects.equals(menu, menu1.menu); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(menu); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return menu; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package menu.domain; | ||
|
||
import static menu.domain.Menu.findMenuByName; | ||
|
||
import camp.nextstep.edu.missionutils.Randoms; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
public class Recommender { | ||
|
||
private static final int SAME_CATEGORY_MAX_COUNT = 2; | ||
private static final int START_BOUND = 1; | ||
|
||
public Menu recommendMenuForCoach(Map<Category, String> map, Category category, Coach coach) { | ||
List<String> categoryMenus = Arrays.stream(map.get(category).split(",")) | ||
.collect(Collectors.toList()); | ||
while (true) { | ||
Menu menu = findMenuByName(categoryMenus, Randoms.shuffle(categoryMenus).get(0)); | ||
if (coach.canNotEatMenu(menu) || coach.isAlreadyRecommended(menu)) { | ||
continue; | ||
} | ||
return menu; | ||
} | ||
} | ||
|
||
public Category pickOneCategory(List<Category> recommendedCategories) { | ||
while (true) { | ||
Category category = Category.valueOf( | ||
Randoms.pickNumberInRange(START_BOUND, Category.values().length)); | ||
if (!isValidCategory(recommendedCategories, category)) { | ||
continue; | ||
} | ||
return category; | ||
} | ||
} | ||
|
||
private boolean isValidCategory(List<Category> recommendedCategories, Category category) { | ||
long count = recommendedCategories.stream().filter(c -> c.equals(category)).count(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분 놓쳤었네요 다 확인했다고 생각했는데 감사합니다! |
||
return count < SAME_CATEGORY_MAX_COUNT; | ||
} | ||
} |
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.
메뉴을 하나의 String 이 아닌 여러 String으로 나누어서 넣어보면 어떨까요?
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.
그런 방법도 있겠네요! 감사합니다😄