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

[점심 메뉴 추천] 김연진 미션 제출합니다. #2

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a9db0f3
docs: 기능 목록 작성
homebdy Aug 23, 2023
6707bda
feat(OutputView): 실행 문구 출력
homebdy Aug 23, 2023
42b65d3
feat(OutputView): 코치 이름 입력 안내 출력
homebdy Aug 23, 2023
6cd6dee
feat(InputView): 코치 이름 입력
homebdy Aug 23, 2023
07fef5f
feat(OutputView): 못 먹는 음식 입력 안내 출력
homebdy Aug 23, 2023
2112d1f
feat(InputView): 못 먹는 음식 입력 구현
homebdy Aug 23, 2023
178222b
feat(Coaches): 코치 이름, 못 먹는 음식 저장
homebdy Aug 23, 2023
5cac751
feat(Category): 카테고리 enum 구현
homebdy Aug 23, 2023
ccbbbab
feat(CategoryRecommender): 카테고리 추천 기능 구현
homebdy Aug 23, 2023
75ddf5e
feat(CategoryRecommender): 이미 2번 먹은 카테고리일 경우 다시 추천
homebdy Aug 23, 2023
f533b87
feat(Menu): 카테고리에 포함된 음식 반환 기능 구현
homebdy Aug 24, 2023
b528758
feat(MenuRecommender): 음식 추천 기능 구현
homebdy Aug 24, 2023
f989cfc
feat(Coach): 코치가 못 먹는 음식인지 판단
homebdy Aug 24, 2023
88bc29a
feat(MenuRecommender): 코치가 못 먹는 음식일 경우 다시 추천
homebdy Aug 24, 2023
842c47e
feat(MenuRecommender): 이미 먹은 음식일 경우 다시 추천
homebdy Aug 24, 2023
5d91324
fix(MenuRecommender): 추천 기능 방식 수정
homebdy Aug 24, 2023
9bb59aa
feat(OutputView): 추천 카테고리 출력
homebdy Aug 24, 2023
a0fbc8d
feat(OutputView): 요일 출력
homebdy Aug 24, 2023
a010efb
feat(OutputView): 결과 안내 메시지 출력
homebdy Aug 24, 2023
65b5401
feat(OutputView): 메뉴 추천 결과 출력
homebdy Aug 24, 2023
683a89f
refactor(MenuService): 메서드 명 변경
homebdy Aug 24, 2023
f860405
feat(Name): 코치의 이름이 2~4글자 이상인 경우 예외 발생
homebdy Aug 24, 2023
dc99f42
feat(InputValidator): `,`로 나누어져 있지 않은 경우 예외 발생
homebdy Aug 24, 2023
d06f536
feat(InputValidator): 정규식 수정
homebdy Aug 24, 2023
7f4c52a
feat(InputView): 오류 발생 시 발생 지점부터 재시작
homebdy Aug 24, 2023
a21fd7f
feat(MenuController): 메서드 분리
homebdy Aug 24, 2023
18286a7
feat(Categories): 클래스명 변경
homebdy Aug 24, 2023
309ef2c
feat(Coaches): getter 제거
homebdy Aug 24, 2023
bb34e0b
refactor(InputView): 에러 출력 방식 변경
homebdy Aug 24, 2023
ed9399a
test(InputValidator): `,`로 나누어져 있지 않은 경우 예외 발생 테스트
homebdy Aug 24, 2023
ff7b356
test(categories): 카테고리 추천 테스트
homebdy Aug 24, 2023
935447d
test(Category): 카테고리 응답 테스트
homebdy Aug 24, 2023
c1f2a99
test(Name): 이름 길이 예외 테스트
homebdy Aug 24, 2023
499da34
fix(InputValidator): 빈 값 입력시 오류 발생 수정
homebdy Aug 24, 2023
84426a0
refactor(RecommendMenu): 메뉴 추천 기능 분리
homebdy Aug 26, 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
27 changes: 27 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
### 구현 기능 목록

**출력**
- [x] 실행 문구
- [x] 이름 입력 안내
- [x] 못 먹는 음식 입력 안내
- [x] 추천 요일
- [x] 추천 카테고리
- [x] 메뉴 추천 결과
- [x] 추천 완료 문구

**입력**
- [x] 코치 이름
- [x] 못 먹는 음식

**카테고리 추천**
- [x] 랜덤으로 카테고리를 뽑는다.
- [x] 3번 이상 먹은 카테고리일 경우 다시 뽑는다.

**음식 추천**
- [x] 카테고리의 음식 중 하나를 뽑는다.
- [x] 코치가 못 먹는 음식일 경우 다시 뽑는다.
- [x] 이미 먹은 음식일 경우 다시 뽑는다.

**오류 발생**
- [x] 코치의 이름이 2~4글자 이상인 경우
- [x] `,`로 나누어져 있지 않은 경우
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.start();
}
}
32 changes: 32 additions & 0 deletions src/main/java/menu/constant/Category.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package menu.constant;

import java.util.Arrays;

public enum Category {

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

private final int index;
private final String type;

Category(int index, String type) {
this.index = index;
this.type = type;
}

public static Category getRecommendFood(int randomNumber) {
return Arrays.stream(Category.values())
.filter(category -> category.index == randomNumber)
.findAny()
.orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.INCORRECT_RECOMMEND.toString()));
}

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

public enum Days {

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

private final String day;

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

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

public enum ExceptionMessage {

INCORRECT_RECOMMEND("잘못된 추천입니다."),
INCORRECT_CATEGORY("존재하지 않는 카테고리입니다."),
INCORRECT_NAME_RANGE("코치의 이름은 2~4자까지 입력할 수 있습니다."),
INCORRECT_DELIMITER("','로 구분해 입력하여 주십시오.");

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

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

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

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

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

private final Category category;
private final List<String> foods;
Menu(Category category, List<String> foods) {
this.category = category;
this.foods = foods;
}

public static List<String> getFoodsByCategory(Category category) {
return Arrays.stream(Menu.values())
.filter(value -> value.category == category)
.findAny()
.orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.INCORRECT_CATEGORY.toString()))
.foods;
}
}
22 changes: 22 additions & 0 deletions src/main/java/menu/constant/OutputMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package menu.constant;

public enum OutputMessage {

START_MESSAGE("점심 메뉴 추천을 시작합니다."),
COACH_NAME("코치의 이름을 입력해 주세요. (, 로 구분)"),
EXCLUDED_FOOD("%s(이)가 못 먹는 메뉴를 입력해 주세요.\n"),
DAYS_TITLE("구분"),
MENU_RESULT("메뉴 추천 결과입니다."),
COMPLETE("추천을 완료했습니다.");

private final String message;

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

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

public enum ResultElement {
START("[ "),
END(" ]"),
DELIMITER(" | ");


private final String element;

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

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

import menu.domain.Name;
import menu.service.MenuService;
import menu.view.InputView;
import menu.view.OutputView;

import java.util.List;

public class MenuController {

private final OutputView outputView = new OutputView();
private final InputView inputView = new InputView();
private final MenuService menuService = new MenuService();

public void start() {
outputView.printStartMessage();
addCoachAndExcludedFoods();
menuService.recommendMenus();
outputView.printResult(menuService.getCategories(), menuService.getCoaches());
}

private void addCoachAndExcludedFoods() {
List<Name> coaches = inputView.readNames();
coaches.forEach(name -> {
outputView.printExcludedFood(name);
menuService.addCoach(name, inputView.readExcludedFood());
outputView.printNewLine();
});
}
}
58 changes: 58 additions & 0 deletions src/main/java/menu/domain/Categories.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package menu.domain;

import camp.nextstep.edu.missionutils.Randoms;
import menu.constant.Category;
import menu.constant.ResultElement;

import java.util.*;

public class Categories {

private static final int RECOMMEND_NUMBER = 5;
private static final int MAX_RECOMMEND_COUNT = 2;
private static final String TITLE = "카테고리";

private final List<Category> categories;
private final Map<Category, Integer> categoriesCount;

public Categories() {
this.categoriesCount = new EnumMap<>(Category.class);
Arrays.stream(Category.values())
.forEach(category -> categoriesCount.put(category, 0));
this.categories = recommendCategory();
}

private List<Category> recommendCategory() {
List<Category> categories = new ArrayList<>();
while (categories.size() < RECOMMEND_NUMBER) {
Category recommendCategory = Category.getRecommendFood(Randoms.pickNumberInRange(1, 5));
if (isNotThreeTimes(recommendCategory)) {
categories.add(recommendCategory);
categoriesCount.put(recommendCategory, increaseCount(recommendCategory));
}
}
return List.copyOf(categories);
}

private boolean isNotThreeTimes(Category recommendCategory) {
return categoriesCount.get(recommendCategory) < MAX_RECOMMEND_COUNT;
}

private int increaseCount(Category category) {
return categoriesCount.get(category) + 1;
}

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

@Override
public String toString() {
StringJoiner stringJoiner = new StringJoiner(ResultElement.DELIMITER.toString(), ResultElement.START.toString(), ResultElement.END.toString());
stringJoiner.add(TITLE);
categories.forEach(
(category) -> stringJoiner.add(category.toString())
);
return stringJoiner.toString();
}
}
32 changes: 32 additions & 0 deletions src/main/java/menu/domain/Coach.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package menu.domain;

import menu.constant.Category;
import menu.constant.ResultElement;

import java.util.List;
import java.util.StringJoiner;

public class Coach {

private final Name name;
private final ExcludedMenu excludedMenu;
private final RecommendMenu recommendMenu;

public Coach(Name name, List<String> excludedFoods) {
this.name = name;
this.excludedMenu = new ExcludedMenu(excludedFoods);
this.recommendMenu = new RecommendMenu();
}

public void recommendFoods(Category category) {
recommendMenu.recommendFoods(category, excludedMenu);
}

@Override
public String toString() {
StringJoiner stringJoiner = new StringJoiner(ResultElement.DELIMITER.toString(), ResultElement.START.toString(), ResultElement.END.toString());
stringJoiner.add(name.toString());
stringJoiner.add(recommendMenu.toString());
return stringJoiner.toString();
}
}
27 changes: 27 additions & 0 deletions src/main/java/menu/domain/Coaches.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package menu.domain;

import menu.constant.Category;

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

public class Coaches {

private static final String NEW_LINE = "\n";
private final List<Coach> coaches = new ArrayList<>();

public void addCoach(Name name, List<String> excludedFoods) {
coaches.add(new Coach(name, excludedFoods));
}

public void recommendMenu(Category category) {
coaches.forEach(coach -> coach.recommendFoods(category));
}

@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
coaches.forEach(coach -> stringBuilder.append(coach.toString()).append(NEW_LINE));
return stringBuilder.toString();
}
}
17 changes: 17 additions & 0 deletions src/main/java/menu/domain/ExcludedMenu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package menu.domain;

import java.util.List;

public class ExcludedMenu {

private final List<String> excludedMenus;


public ExcludedMenu(List<String> excludedMenus) {
this.excludedMenus = excludedMenus;
}

public boolean isExcludedMenu(String recommendMenu) {
return excludedMenus.contains(recommendMenu);
}
}
28 changes: 28 additions & 0 deletions src/main/java/menu/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package menu.domain;

import menu.constant.ExceptionMessage;

public class Name {

private static final int MIN_NAME_LENGTH = 2;
private static final int MAX_NAME_LENGTH = 4;

private final String name;

public Name(String name) {
validateName(name);
this.name = name;
}

private void validateName(String name) {
if (!(MIN_NAME_LENGTH <= name.length() && name.length() <= MAX_NAME_LENGTH)) {
ExceptionMessage exceptionMessage = ExceptionMessage.INCORRECT_NAME_RANGE;
throw new IllegalArgumentException(exceptionMessage.toString());
}
}

@Override
public String toString() {
return name;
}
}
Loading