Skip to content

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

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

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bc64174
docs(README): 기능 목록 추가
ohksj77 Sep 18, 2023
724c685
feat(GameMessage): 메시지 열거형 추가
ohksj77 Sep 18, 2023
3eecde0
feat(OutputView): 시작 메시지 출력 기능
ohksj77 Sep 18, 2023
d26a255
feat(MenuController): 컨트롤러 클래스 추가
ohksj77 Sep 18, 2023
46b1f06
feat: 코치 이름 입력 요청 메시지 출력 기능
ohksj77 Sep 18, 2023
2db41ae
feat(ErrorMessage): 에러 메시지 열거형 추가
ohksj77 Sep 18, 2023
657b23c
feat(Coach): 코치 이름 검증 기능 및 도메인 추가
ohksj77 Sep 18, 2023
28b10f2
feat(Coaches): 코치 인원수 검증 및 일급 컬렉션 추가
ohksj77 Sep 18, 2023
cadf4c7
feat(InputValidator): 쉼표 구분자 검증 기능
ohksj77 Sep 18, 2023
c125095
feat(InputView): 코치 이름 입력 기능
ohksj77 Sep 18, 2023
a2192b8
feat(InputManager): 코치 이름 재시도 기능 추가
ohksj77 Sep 18, 2023
350d752
feat(MenuService): 코치 저장 기능 및 서비스 클래스 추가
ohksj77 Sep 18, 2023
c76f95a
feat(MenuRepository): 코치 저장 기능 및 저장소 클래스 추가
ohksj77 Sep 18, 2023
f6482f0
feat: 코치 입력값 저장소 클래스에 저장 기능
ohksj77 Sep 18, 2023
b1e4ced
feat: 코치별 못먹는 메뉴 입력 요청 메시지 출력
ohksj77 Sep 18, 2023
4c83baa
feat(Menu): 메뉴 도메인 추가
ohksj77 Sep 18, 2023
b9b916e
feat(HateMenus): 코치의 못먹는 메뉴 개수 검증 및 일급 컬렉션 추가
ohksj77 Sep 18, 2023
7a31f14
feat: 코치 못먹는 음식 입력 기능
ohksj77 Sep 18, 2023
59c2de3
feat(MenuCategory): 메뉴 카테고리 열거형 추가
ohksj77 Sep 18, 2023
f283e6b
feat: 존재하는 메뉴인지 검증 기능
ohksj77 Sep 18, 2023
bf2a11b
feat: 코치 못먹는 메뉴 업데이트 기능
ohksj77 Sep 18, 2023
e0e44c1
feat(RandomMenuGenerator): 랜덤 메뉴 생성 기능
ohksj77 Sep 18, 2023
b48eea2
feat(MenuCategories): 생성된 카테고리 관리 일급 컬렉션
ohksj77 Sep 18, 2023
774a8c0
feat: 추천 메뉴 도메인 추가
ohksj77 Sep 18, 2023
a48497e
feat(RecommendResult): 결과 도메인 추가
ohksj77 Sep 18, 2023
96e1f8f
feat: 메뉴 추천 기능
ohksj77 Sep 18, 2023
8fb7e51
feat: 기능 연결 완료
ohksj77 Sep 18, 2023
36e5162
test: 테스트 추가
ohksj77 Sep 18, 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
79 changes: 79 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
## 기능 목록
- [x] 시작 메시지 출력
- [x] 코치 이름 입력 요청 메시지 출력
- [x] 코치 이름 입력
- [x] 코치 이름 입력값 쉼표로 구분됐는지 검증
- [x] 코치 이름 길이 2 ~ 4 사이인지 검증
- [x] 코치 5명 이하인지 검증
- [x] 잘못된 입력시 에러 메시지 출력 및 재시도
- [x] 코치별 못 먹는 메뉴 입력 요청 메시지 출력
- [x] 코치별 못 먹는 메뉴 입력
- [x] 개수 0 ~ 2개 사이인지 검증
- [x] 메뉴 목록에 포함된 메뉴인지 검증
- [x] 잘못된 입력시 에러 메시지 출력 및 재시도
- [x] 메뉴 추천
- [x] 랜덤 메뉴 생성
- [x] 한 주에 같은 카테고리 최대 2회인지 검증
- [x] 각 코치에게 중복된 메뉴가 없는지 검증
- [x] 추천 완료 메시지 출력

## 구현 클래스

- MenuController
- run()

- OutputView
- printStart()
- printCoachNameRequest()

- Coach
- getName()
- hasName()
- updateHateMenus()
- getHateMenus()
- updateRecommendedMenus()

- Coaches
- getNextCoachName()
- hasNext()
- findByName()
- initIndex()
- getNextCoach()

- InputValidator
- validateInputDelimiter()

- InputView
- readCoachNames()

- InputManager
- readCoachNames()

- MenuService
- saveCoaches()

- MenuRepository
- saveCoaches()

- Menu
- getName()

- HateMenus

- RandomMenuGenerator

- RecommendedMenus
- addMenu()

- MenuCategories
- hasMaxNum()
- addRecommendedMenus()
- needNext()

- RecommendResult
- getResult()

## 열거형 목록
- GameMessage
- ErrorMessage
- MenuCategory
4 changes: 3 additions & 1 deletion src/main/java/menu/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package menu;

import menu.controller.MenuController;

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

public enum ErrorMessage {
INVALID_COACH_NAME_LENGTH("코치 이름 길이가 잘못되었습니다."),
INVALID_COACH_NUM("코치의 인원수가 잘못되었거나 중복 코치이름이 있습니다."),
INVALID_INPUT_DELIMITER_USAGE("쉼표는 맨 처음이나 끝에 올 수 없습니다."),
INVALID_MENU_SIZE("못 먹는 메뉴의 개수가 잘못되었습니다."),
INVALID_MENU_NAME("존재하지 않는 메뉴입니다."),
INVALID_COACH_NAME("존재하지 않는 코치 이름입니다."),
INVALID_CATEGORY_INDEX("카테고리 인덱스가 잘못되었습니다.");

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

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

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

public enum GameMessage {
START("점심 메뉴 추천을 시작합니다."),
COACH_NAME_REQUEST("코치의 이름을 입력해 주세요. (, 로 구분)"),
COACH_HATE_MENU_REQUEST("%s(이)가 못 먹는 메뉴를 입력해 주세요."),
MENU_RECOMMEND_RESULT("메뉴 추천 결과입니다."),
RECOMMEND_DAYS("[ 구분 | 월요일 | 화요일 | 수요일 | 목요일 | 금요일 ]"),
RECOMMEND_FINISH("추천을 완료했습니다.");

private final String message;

GameMessage(final String message) {
this.message = message;
}

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

import menu.domain.HateMenus;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

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

private final int index;
private final String category;
private final List<String> menus;

MenuCategory(final int index, final String category, final List<String> menus) {
this.index = index;
this.category = category;
this.menus = menus;
}

public static boolean isNotExistMenu(final String menuName) {
return Arrays.stream(values())
.noneMatch(mc -> mc.menus.contains(menuName));
}

public List<String> getMenusFiltered(final HateMenus hateMenus) {
return this.menus.stream()
.filter(hateMenus::hasNoSameMenu)
.collect(Collectors.toList());
}

public static MenuCategory getByIndex(final int index) {
return Arrays.stream(values())
.filter(mc -> mc.index == index)
.findAny()
.orElseThrow(() -> new IllegalArgumentException(ErrorMessage.INVALID_CATEGORY_INDEX.getMessage()));
}

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

import menu.domain.Coaches;
import menu.domain.HateMenus;
import menu.domain.RecommendResult;
import menu.io.InputManager;
import menu.io.OutputView;
import menu.service.MenuService;

public class MenuController {

private final OutputView outputView = new OutputView();
private final InputManager inputManager = new InputManager();
private final MenuService menuService = new MenuService();

public void run() {
outputView.printStart();
final Coaches coaches = createCoaches();
createHateMenu(coaches);
recommendMenu();
}

private void recommendMenu() {
final RecommendResult recommendResult = menuService.recommendMenu();
outputView.printRecommendResult(recommendResult);
}

private void createHateMenu(final Coaches coaches) {
while (!coaches.isLast()) {
final String coachName = coaches.getNextCoachName();
outputView.printCoachHateMenuRequest(coachName);
final HateMenus hateMenus = inputManager.readCoachHateMenu();
menuService.updateHateMenus(coachName, hateMenus);
}
}

private Coaches createCoaches() {
outputView.printCoachNameRequest();
final Coaches coaches = inputManager.readCoachNames();
return menuService.saveCoaches(coaches);
}
}
68 changes: 68 additions & 0 deletions src/main/java/menu/domain/Coach.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package menu.domain;

import menu.constant.ErrorMessage;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class Coach {

private static final int MIN_NAME_LENGTH = 2;
private static final int MAX_NAME_LENGTH = 4;
private final String name;
private HateMenus hateMenus;
private RecommendedMenus recommendedMenus;

public Coach(final String name) {
validateName(name);
this.name = name;
this.recommendedMenus = new RecommendedMenus();
}

private void validateName(final String name) {
final int length = name.length();
if (MIN_NAME_LENGTH > length || length > MAX_NAME_LENGTH) {
throw new IllegalArgumentException(ErrorMessage.INVALID_COACH_NAME_LENGTH.getMessage());
}
}

public String getName() {
return this.name;
}

public boolean hasName(final String coachName) {
return this.name.equals(coachName);
}

public void updateHateMenus(final HateMenus hateMenus) {
this.hateMenus = hateMenus;
}

public HateMenus getHateMenus() {
return this.hateMenus;
}

public void updateRecommendedMenus(final String menus) {
this.recommendedMenus.addMenu(menus);
}

public List<String> getRecommendedMenus() {
return this.recommendedMenus.getMenus().stream()
.map(Menu::getName)
.collect(Collectors.toList());
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Coach coach = (Coach) o;
return Objects.equals(name, coach.name);
}

@Override
public int hashCode() {
return Objects.hash(name);
}
}
64 changes: 64 additions & 0 deletions src/main/java/menu/domain/Coaches.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package menu.domain;

import menu.constant.ErrorMessage;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;

public class Coaches {

private static final int MIN_COACH_NUM = 2;
private static final int MAX_COACH_NUM = 5;
private static final int INIT_INDEX = 0;
private final List<Coach> coaches;
private int currentIndex;

public Coaches(final List<Coach> coaches) {
validate(coaches);
this.coaches = Collections.unmodifiableList(coaches);
this.currentIndex = INIT_INDEX;
}

private void validate(final List<Coach> coaches) {
final int size = coaches.size();
if (size < MIN_COACH_NUM || size > MAX_COACH_NUM || new HashSet<>(coaches).size() != coaches.size()) {
throw new IllegalArgumentException(ErrorMessage.INVALID_COACH_NUM.getMessage());
}
}

public String getNextCoachName() {
checkCurrentIndex();
return coaches.get(currentIndex++).getName();
}

private void checkCurrentIndex() {
if (currentIndex == coaches.size()) {
currentIndex = INIT_INDEX;
}
}

public boolean isLast() {
final boolean flag = currentIndex == coaches.size();
if (flag) {
currentIndex = INIT_INDEX;
}
return flag;
}

public Coach findByName(final String coachName) {
return this.coaches.stream()
.filter(coach -> coach.hasName(coachName))
.findAny()
.orElseThrow(() -> new IllegalStateException(ErrorMessage.INVALID_COACH_NAME.getMessage()));
}

public Coach getNextCoach() {
checkCurrentIndex();
return this.coaches.get(currentIndex++);
}

public List<Coach> getCoaches() {
return this.coaches;
}
}
29 changes: 29 additions & 0 deletions src/main/java/menu/domain/HateMenus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package menu.domain;

import menu.constant.ErrorMessage;

import java.util.List;
import java.util.stream.Collectors;

public class HateMenus {

private static final int MAX_HATE_MENU_SIZE = 2;
private final List<Menu> menus;

public HateMenus(final List<String> menus) {
validateSize(menus);
this.menus = menus.stream().map(Menu::new).collect(Collectors.toList());
}

private void validateSize(final List<String> menus) {
if (menus.size() > MAX_HATE_MENU_SIZE) {
throw new IllegalArgumentException(ErrorMessage.INVALID_MENU_SIZE.getMessage());
}
}

public boolean hasNoSameMenu(final String menuName) {
return menus.stream()
.map(Menu::getName)
.noneMatch(menuName::equals);
}
}
Loading