Skip to content
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

[점심 메뉴 추천] 박준수 미션 제출합니다. #3

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
b2fbb7a
docs: 기능목록/에러처리 정의
GaBaljaintheroom Aug 30, 2023
4675817
feat: InputView inputCoachName 작성
GaBaljaintheroom Aug 30, 2023
7ce87d5
feat: OutputView 생성
GaBaljaintheroom Aug 30, 2023
18f7aa7
feat: InputValidator validateCommaContain 작성
GaBaljaintheroom Aug 30, 2023
c573db7
feat: CoachNames 생성
GaBaljaintheroom Aug 30, 2023
1c26ad8
feat: ErrorMessage 생성
GaBaljaintheroom Aug 30, 2023
f72b962
feat: ProcessMessage 생성
GaBaljaintheroom Aug 30, 2023
537bd2e
test: 코치 이름이 ','로 구분되어 입력 받지 못하면 에러가 발생
GaBaljaintheroom Aug 30, 2023
abe8685
test: CoachNameTest 작성
GaBaljaintheroom Aug 30, 2023
64cced4
docs: 코치 이름 입력
GaBaljaintheroom Aug 30, 2023
ddb9812
feat: InputView inputForbiddenMenu 작성
GaBaljaintheroom Aug 30, 2023
f7e734a
feat: OutputView printCoachesForbiddenMenu 작성
GaBaljaintheroom Aug 30, 2023
48180f9
feat: ProcessMessage INPUT_FORBIDDEN_MENU작성
GaBaljaintheroom Aug 30, 2023
9e3c809
feat: InputValidator validateForbiddenMenuCount 작성
GaBaljaintheroom Aug 30, 2023
c06ea3d
feat: ForbiddenMenu 생성
GaBaljaintheroom Aug 30, 2023
5372043
test: 못 먹는 메뉴의 개수가 최소 0개, 최대 2개가 아니면 에러가 발생
GaBaljaintheroom Aug 30, 2023
52dedf2
test: ForbiddenMenuTest 코치 별로 못 먹는 메뉴가 저장되는지 확인
GaBaljaintheroom Aug 30, 2023
f9022c2
docs: 각 코치가 못 먹는 메뉴를 입력
GaBaljaintheroom Aug 30, 2023
a1d5ef8
feat: Days 생성
GaBaljaintheroom Aug 30, 2023
e72d19d
feat: Categories 생성
GaBaljaintheroom Aug 30, 2023
3f0cf72
feat: RecommendCategory 생성
GaBaljaintheroom Aug 30, 2023
bd56796
test: 추천 카테고리가 카테고리 수 만큼 저장이 되는지 확인
GaBaljaintheroom Aug 30, 2023
1f3d65c
docs: 카테고리 생성
GaBaljaintheroom Aug 30, 2023
d632059
feat: Menus 생성
GaBaljaintheroom Aug 30, 2023
ca660ff
feat: RecommendMenu 생성
GaBaljaintheroom Aug 30, 2023
884eb93
feat: ForbiddenMenu isNotContainForbiddenMenu 작성
GaBaljaintheroom Aug 30, 2023
c639b0e
feat: RecommendCategory getCategoryCount 추가
GaBaljaintheroom Aug 30, 2023
5143eef
test: 못 먹는 음식이 없을 경우 true를 반환
GaBaljaintheroom Aug 30, 2023
8f423a8
test: 추천된 메뉴가 코치 수 만큼 저장되는지 확인
GaBaljaintheroom Aug 30, 2023
75c7754
docs: 추천
GaBaljaintheroom Aug 30, 2023
954e647
feat: main 함수 작성
GaBaljaintheroom Aug 30, 2023
286a012
feat: Categories outputCategories 작성
GaBaljaintheroom Aug 30, 2023
43150cc
feat: Days outputDays 작성
GaBaljaintheroom Aug 30, 2023
90201e0
feat: InputView printEnter 추가
GaBaljaintheroom Aug 30, 2023
695e065
feat: RecommendMenu toString 추가
GaBaljaintheroom Aug 30, 2023
49144e4
feat: MenuController 생성
GaBaljaintheroom Aug 30, 2023
aa0bc6f
feat: OutputElement 생성
GaBaljaintheroom Aug 30, 2023
1ce2c9d
feat: ProcessMessage 추가
GaBaljaintheroom Aug 30, 2023
cd3d868
feat: OutputView 추가
GaBaljaintheroom Aug 30, 2023
c70a700
refactor: Category 출력이동
GaBaljaintheroom Aug 30, 2023
1e704a3
refactor: RecommendCategory toString 추가
GaBaljaintheroom Aug 30, 2023
56740fe
refactor: Input 형식 수정
GaBaljaintheroom Aug 30, 2023
c845633
refactor: 패키지 구조 변경
GaBaljaintheroom Aug 30, 2023
a177d58
test: 추천 카테고리에 카테고리 중 일부가 저장되는지 확인
GaBaljaintheroom Aug 31, 2023
b8ddd6f
refactor: StartRecommend 수정
GaBaljaintheroom Aug 31, 2023
e4c9309
refactor: RecommendCategory curCategory 추가
GaBaljaintheroom Aug 31, 2023
21da46b
refactor: RecommendMenu createRecommendMenu 수정
GaBaljaintheroom Aug 31, 2023
85f6a99
refactor: 추천 카테고리가 카테고리 수 만큼 저장이 되는지 확인 테스트 수정
GaBaljaintheroom Aug 31, 2023
bc9278c
refactor: 상수 처리 추가
GaBaljaintheroom Aug 31, 2023
47332ca
test: 숫자에 맞는 카테고리 타입이 반환되는지 확인
GaBaljaintheroom Aug 31, 2023
29294e7
test: type에 맞는 음식들이 반환되는지 확인
GaBaljaintheroom Aug 31, 2023
8ca987e
refactor: 읽기 전용 빈 리스트로 수정
GaBaljaintheroom Aug 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 우테코 menu 문제

## 기능 목록
- inputView
- [x] 메뉴 추천 받을 코치 이름 입력
- [x] 코치 이름은 최소 2글자, 최대 4글자이다.
- [x] 코치는 최소 2명, 최대 5명까지 식사를 함께 한다.
- [x] 각 코치가 못 먹는 메뉴를 입력
- [x] 최소 0개, 최대 2개까지 못 먹는 메뉴가 있다. (, 로 구분해서 입력한다.)

- outputView
- 메뉴 추천 결과 출력

- recommend
- [x] 월, 화, 수, 목, 금 각 요일 마다 추천할 카테고리를 무작위로 정한다.
- [x] 각 코치가 요일에 먹을 메뉴를 추천한다.

- category
- [x] 한 주에 같은 카테고리는 최대 2회까지만 고르며 생성

- menu
- [x] 각 코치에게 한 주에 중복되지 않는 메뉴를 추천해야 한다.

## 에러 처리

- inputValidator
- [x] 잘못된 값을 입력할 경우 `IllegalArgumentException`를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.
- [x] 코치 이름은 최소 2글자, 최대 4글자이다.
- [x] 코치는 최소 2명, 최대 5명까지 식사를 함께 한다.
- [x] 최소 0개, 최대 2개까지 못 먹는 메뉴가 있다. (, 로 구분해서 입력한다.)
5 changes: 4 additions & 1 deletion src/main/java/menu/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package menu;

import menu.controller.MenuController;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
MenuController menuController = new MenuController();
menuController.StartRecommend();
}
}
37 changes: 37 additions & 0 deletions src/main/java/menu/constant/Categories.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package menu.constant;

import java.util.Arrays;
import java.util.function.Predicate;

public enum Categories {
JAPANESE(1, "일식"),
KOREAN(2, "한식"),
CHINESE(3, "중식"),
ASIAN(4, "아시안"),
WESTERN(5, "양식");


private final int number;
private final String type;

Categories(int number, String type) {
this.number = number;
this.type = type;
}

public static String getType(int number) {
return Arrays.stream(Categories.values())
.filter(isSameNumber(number))
.map(categories -> categories.type)
.findFirst()
.orElse(null);
}

private static Predicate<Categories> isSameNumber(int number) {
return categories -> categories.number == number;
}

public String findType(){
return type;
}
}
27 changes: 27 additions & 0 deletions src/main/java/menu/constant/Days.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package menu.constant;

public enum Days {
MONDAY("월요일"),
TUESDAY("화요일"),
WEDNESDAY("수요일"),
THURSDAY("목요일"),
FRIDAY("금요일");

private static final String DIVISION = "구분";
private final String value;

Days(String value) {
this.value = value;
}

public static String outputDays() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(OutputElement.FIRST_ELEMENT).append(DIVISION);
for (Days days :Days.values()){
stringBuilder.append(OutputElement.MIDDLE_ELEMENT)
.append(days.value);
}
stringBuilder.append(OutputElement.LAST_ELEMENT);
return stringBuilder.toString();
}
}
21 changes: 21 additions & 0 deletions src/main/java/menu/constant/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package menu.constant;

public enum ErrorMessage {

COACH_NAME_LENGTH_ERROR("코치 이름은 %d~%d글자 사이로 입력되어야 합니다."),
COACH_NAME_NUMBER_ERROR("코치는 최소 %d명, 최대 %d명 입력되어야 합니다."),

INPUT_COMMA_ERROR("',' 로 구분되어 이름을 입력해주세요.");

private static final String prefix = "[ERROR] ";
private final String message;

ErrorMessage(String message) {
this.message = message;
}

@Override
public String toString() {
return prefix + message;
}
}
33 changes: 33 additions & 0 deletions src/main/java/menu/constant/Menus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package menu.constant;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public enum Menus {
JAPANESE("일식", List.of("규동", "우동", "미소시루", "스시", "가츠동", "오니기리", "하이라이스", "라멘", "오코노미야끼")),
KOREAN("한식", List.of("김밥", "김치찌개", "쌈밥", "된장찌개", "비빔밥", "칼국수", "불고기", "떡볶이", "제육볶음")),
CHINES("중식", List.of("깐풍기", "볶음면", "동파육", "짜장면", "짬뽕", "마파두부", "탕수육", "토마토 달걀볶음", "고추잡채")),
ASIAN("아시안", List.of("팟타이", "카오 팟", "나시고렝", "파인애플 볶음밥", "쌀국수", "똠얌꿍", "반미", "월남쌈", "분짜")),
WESTERN("양식", List.of("라자냐", "그라탱", "뇨끼", "끼슈", "프렌치 토스트", "바게트", "스파게티", "피자", "파니니"));

private final String type;
private final List<String> foods;

Menus(String type, List<String> foods) {
this.type = type;
this.foods = foods;
}

public static List<String> getFoods(String type) {
return Arrays.stream(Menus.values())
.filter(isSameType(type))
.map(menus -> menus.foods)
.findFirst()
.orElse(null);
}

private static Predicate<Menus> isSameType(String type) {
return menus -> menus.type.equals(type);
}
}
20 changes: 20 additions & 0 deletions src/main/java/menu/constant/OutputElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package menu.constant;

public enum OutputElement {
FIRST_ELEMENT("[ "),
MIDDLE_ELEMENT(" | "),
LAST_ELEMENT(" ]"),
NEXT_ELEMENT("\n");


private final String element;

OutputElement(String element) {
this.element = element;
}

@Override
public String toString() {
return element;
}
}
20 changes: 20 additions & 0 deletions src/main/java/menu/constant/ProcessMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package menu.constant;

public enum ProcessMessage {
INPUT_COACH_NAME("코치의 이름을 입력해 주세요. (, 로 구분)"),
INPUT_FORBIDDEN_MENU("%s(이)가 못 먹는 메뉴를 입력해 주세요."),
OUTPUT_START_MENU("점심 메뉴 추천을 시작합니다."),
OUTPUT_RESULT_MENU("메뉴 추천 결과입니다."),
OUTPUT_FINISH_MENU("추천을 완료했습니다.");

private final String message;

ProcessMessage(String message) {
this.message = message;
}

@Override
public String toString() {
return message;
}
}
35 changes: 35 additions & 0 deletions src/main/java/menu/controller/MenuController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package menu.controller;

import menu.model.CoachNames;
import menu.model.ForbiddenMenu;
import menu.model.RecommendCategory;
import menu.model.RecommendMenu;
import menu.view.InputView;
import menu.view.OutputView;

public class MenuController {

private final InputView inputView;
private final OutputView outputView;
private final RecommendCategory recommendCategory;
private final RecommendMenu recommendMenu;

public MenuController() {
this.inputView = new InputView();
this.outputView = new OutputView();
this.recommendCategory = new RecommendCategory();
this.recommendMenu = new RecommendMenu();
}

public void StartRecommend(){
outputView.printStartMenu();
CoachNames coachNames = inputView.readCoachName();
ForbiddenMenu forbiddenMenu = inputView.readForbiddenMenu(coachNames);

while (recommendCategory.isRecommending()){
recommendCategory.createRecommendCategory();
recommendMenu.createRecommendMenu(coachNames, forbiddenMenu, recommendCategory);
}
outputView.printRecommendResult(recommendMenu, recommendCategory);
}
}
46 changes: 46 additions & 0 deletions src/main/java/menu/model/CoachNames.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package menu.model;

import menu.constant.ErrorMessage;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CoachNames {

private final static int MIN_NAME_LENGTH = 2;
private final static int MAX_NAME_LENGTH = 4;
private final static int MIN_COACH_COUNT = 2;
private final static int MAX_COACH_COUNT = 5;
private final static String BY_COMMA = ",";
private final List<String> coachNames = new ArrayList<>();

public CoachNames(String name) {
Arrays.stream(name.split(BY_COMMA))
.forEach(this::addValidateCoachName);
validateCoachNumber();
}

private void addValidateCoachName(String name){
validateCoachNameLength(name);
coachNames.add(name);
}

private void validateCoachNameLength(String name) {
if (name.length() < MIN_NAME_LENGTH || name.length() > MAX_NAME_LENGTH) {
throw new IllegalArgumentException(
String.format(ErrorMessage.COACH_NAME_LENGTH_ERROR.toString(), MIN_NAME_LENGTH, MAX_NAME_LENGTH));
}
}

private void validateCoachNumber(){
if (coachNames.size() < MIN_COACH_COUNT || coachNames.size() > MAX_COACH_COUNT){
throw new IllegalArgumentException(
String.format(ErrorMessage.COACH_NAME_NUMBER_ERROR.toString(), MIN_COACH_COUNT, MAX_COACH_COUNT));
}
}

public List<String> getCoachNames() {
return coachNames;
}
}
24 changes: 24 additions & 0 deletions src/main/java/menu/model/ForbiddenMenu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package menu.model;

import java.util.*;
import java.util.stream.Collectors;

public class ForbiddenMenu {

private final Map<String, List<String>> forbiddenMenus = new HashMap<>();

public void add(String name, String forbiddenMenu) {
forbiddenMenus.put(name, Arrays.stream(forbiddenMenu.split(",")).collect(Collectors.toList()));
}

public boolean isNotContainForbiddenMenu(String name, String menu){
return forbiddenMenus
.getOrDefault(name, Collections.emptyList())
.stream()
.noneMatch(forbiddenMenu -> forbiddenMenu.equals(menu));
}

public Map<String, List<String>> getForbiddenMenus() {
return forbiddenMenus;
}
}
66 changes: 66 additions & 0 deletions src/main/java/menu/model/RecommendCategory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package menu.model;

import camp.nextstep.edu.missionutils.Randoms;
import menu.constant.Categories;
import menu.constant.OutputElement;

import java.util.ArrayList;
import java.util.List;

public class RecommendCategory {

private static final String CATEGORY = "카테고리";
private static final int CATEGORY_COUNT = 5;
private static final int MAX_DUPLICATE_COUNT = 2;
private final List<String> categories = new ArrayList<>();
private int curCategory = 0;

public void createRecommendCategory() {
String newCategory = Categories.getType(Randoms.pickNumberInRange(1, 5));
if (canAddCategory(newCategory)){
categories.add(newCategory);
}
}

private boolean canAddCategory(String newCategory) {
long count = categories.stream()
.filter(category -> category.equals(newCategory))
.count();
return count < MAX_DUPLICATE_COUNT;
}

public boolean isRecommending(){
return categories.size() < CATEGORY_COUNT;
}

public void nextCategory(){
curCategory++;
}

public int getCurCategory() {
return curCategory;
}


public List<String> getCategories() {
return categories;
}

public int getCategoryCount(){
return categories.size();
}

@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(OutputElement.FIRST_ELEMENT).append(CATEGORY);
for (String category : categories){
stringBuilder.append(OutputElement.MIDDLE_ELEMENT)
.append(category);
}
stringBuilder.append(OutputElement.LAST_ELEMENT);
return stringBuilder.toString();
}
}


Loading