Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 2 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ dependencies {
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

test {
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
8 changes: 7 additions & 1 deletion src/main/java/menu/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package menu;

import menu.view.InputView;
import menu.view.OutputView;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
InputView inputView = new InputView();
OutputView outputView = new OutputView();
MenuRecommendation menuRecommendation = new MenuRecommendation(inputView, outputView);
menuRecommendation.run();
}
}
72 changes: 72 additions & 0 deletions src/main/java/menu/MenuRecommendation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package menu;

import java.util.List;
import java.util.function.Supplier;
import menu.domain.FoodCategory;
import menu.domain.ImpossibilityMenu;
import menu.domain.ImpossibilityMenus;
import menu.domain.MenuRecommender;
import menu.domain.Person;
import menu.domain.Persons;
import menu.domain.RecommendMenus;
import menu.domain.RecommendationFoodCategories;
import menu.view.InputView;
import menu.view.OutputView;

public class MenuRecommendation {

private final InputView inputView;
private final OutputView outputView;

public MenuRecommendation(InputView inputView, OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}

public void run() {
outputView.printStartApplication();
Persons persons = retryOnError(this::getPersons);
MenuRecommender menuRecommender = getMenuRecommender(persons);

RecommendationFoodCategories recommendationFoodCategories = new RecommendationFoodCategories();
List<FoodCategory> categories = recommendationFoodCategories.getRecommendationFoodCategories();

RecommendMenus recommendMenus = new RecommendMenus(persons);
for (FoodCategory category : categories) {
for (Person person : persons.getPersons()) {
String menu = menuRecommender.recommendMenu(person, category, recommendMenus);
recommendMenus.addMenu(person, menu);
}
}
outputView.printRecommendationResult(categories, recommendMenus.getRecommendMenus());
}

private <T> T retryOnError(Supplier<T> supplier) {
while (true) {
try {
return supplier.get();
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e.getMessage());
}
}
}

private Persons getPersons() {
List<String> personNames = inputView.readPersonNames();
return new Persons(personNames);
}

private MenuRecommender getMenuRecommender(Persons persons) {
ImpossibilityMenus impossibilityMenus = new ImpossibilityMenus();
for (Person person : persons.getPersons()) {
ImpossibilityMenu menu = retryOnError(() -> getImpossibilityMenu(person));
impossibilityMenus.addImpossibilityMenu(person, menu);
}
return new MenuRecommender(impossibilityMenus);
}

private ImpossibilityMenu getImpossibilityMenu(Person person) {
List<String> menus = inputView.readImpossibilityMenuName(person.getName());
return new ImpossibilityMenu(menus);
}
}
49 changes: 49 additions & 0 deletions src/main/java/menu/domain/FoodCategory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package menu.domain;

import java.util.Arrays;
import menu.exception.ErrorCode;

public enum FoodCategory {

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

private final int number;
private final String name;

FoodCategory(int number, String name) {
this.number = number;
this.name = name;
}

public static FoodCategory from(int number) {
return Arrays.stream(values())
.filter(category -> category.number == number)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(ErrorCode.INVALID_NUMBER.getMessage()));
}

public static int getFirstNumber() {
return Arrays.stream(values())
.map(category -> category.number)
.sorted()
.toList()
.get(0);
}

public static int getLastNumber() {
return Arrays.stream(values())
.map(category -> category.number)
.sorted((o1, o2) -> o2 - o1)
.toList()
.get(0);
}

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

import java.util.List;
import menu.exception.ErrorCode;

public class ImpossibilityMenu {

public static final int MAX_IMPOSSIBILITY_MENUS_COUNT = 2;

private final List<String> impossibilityMenus;

public ImpossibilityMenu(List<String> impossibilityMenus) {
validate(impossibilityMenus);
impossibilityMenus.forEach(MenuBoard::validateMenuName);
this.impossibilityMenus = impossibilityMenus;
}

private void validate(List<String> impossibilityMenus) {
if (impossibilityMenus.size() > MAX_IMPOSSIBILITY_MENUS_COUNT) {
throw new IllegalArgumentException(ErrorCode.INVALID_MAX_IMPOSSIBILITY_MENUS_COUNT.getMessage());
}
}

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

import java.util.HashMap;
import java.util.Map;

public class ImpossibilityMenus {

private final Map<Person, ImpossibilityMenu> impossibilityMenus;

public ImpossibilityMenus() {
this.impossibilityMenus = new HashMap<>();
}

public void addImpossibilityMenu(Person person, ImpossibilityMenu menus) {
impossibilityMenus.put(person, menus);
}

public ImpossibilityMenu getImpossibilityMenu(Person person) {
return impossibilityMenus.get(person);
}
}
39 changes: 39 additions & 0 deletions src/main/java/menu/domain/MenuBoard.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package menu.domain;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.List;
import java.util.Map;
import menu.exception.ErrorCode;

public class MenuBoard {

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

private MenuBoard() {
}

public static void validateMenuName(String menuName) {
List<Boolean> isContains = menuBoard.values().stream()
.map(menus -> menus.contains(menuName))
.toList();
if (!isContains.contains(true)) {
throw new IllegalArgumentException(ErrorCode.INVALID_MENU_NAME.getMessage());
}
}

public static String getMenusExcluding(FoodCategory category, ImpossibilityMenu impossibilityMenus) {
List<String> menus = menuBoard.get(category);
while (true) {
String menu = Randoms.shuffle(menus).get(0);
if (!impossibilityMenus.contains(menu)) {
return menu;
}
}
}
}
21 changes: 21 additions & 0 deletions src/main/java/menu/domain/MenuRecommender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package menu.domain;

public class MenuRecommender {

private final ImpossibilityMenus impossibilityMenus;

public MenuRecommender(ImpossibilityMenus impossibilityMenus) {
this.impossibilityMenus = impossibilityMenus;
}

public String recommendMenu(Person person, FoodCategory category, RecommendMenus recommendMenus) {
ImpossibilityMenu impossibilityMenu = impossibilityMenus.getImpossibilityMenu(person);
String menu = null;
boolean recommended = true;
while (recommended) {
menu = MenuBoard.getMenusExcluding(category, impossibilityMenu);
recommended = recommendMenus.containsMenu(person, menu);
}
return menu;
}
}
29 changes: 29 additions & 0 deletions src/main/java/menu/domain/Person.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package menu.domain;

import menu.exception.ErrorCode;

public class Person {

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

private final String name;

public Person(String name) {
validate(name);
this.name = name;
}

private void validate(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException(ErrorCode.INVALID_NAME.getMessage());
}
if (name.length() < MIN_NAME_LENGTH || name.length() > MAX_NAME_LENGTH) {
throw new IllegalArgumentException(ErrorCode.INVALID_NAME_LENGTH.getMessage());
}
}

public String getName() {
return name;
}
}
32 changes: 32 additions & 0 deletions src/main/java/menu/domain/Persons.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package menu.domain;

import java.util.List;
import menu.exception.ErrorCode;

public class Persons {

public static final int MIN_PERSONS_COUNT = 2;
public static final int MAX_PERSONS_COUNT = 5;

private final List<Person> persons;

public Persons(List<String> names) {
validate(names);
this.persons = names.stream()
.map(Person::new)
.toList();
}

private void validate(List<String> names) {
if (names.size() < MIN_PERSONS_COUNT) {
throw new IllegalArgumentException(ErrorCode.INVALID_MIN_PERSONS_COUNT.getMessage());
}
if (names.size() > MAX_PERSONS_COUNT) {
throw new IllegalArgumentException(ErrorCode.INVALID_MAX_PERSONS_COUNT.getMessage());
}
}

public List<Person> getPersons() {
return persons;
}
}
30 changes: 30 additions & 0 deletions src/main/java/menu/domain/RecommendMenus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package menu.domain;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class RecommendMenus {

private final Map<Person, List<String>> recommendMenus;

public RecommendMenus(Persons persons) {
this.recommendMenus = new LinkedHashMap<>();
for (Person person : persons.getPersons()) {
recommendMenus.put(person, new ArrayList<>());
}
}

public boolean containsMenu(Person person, String menu) {
return recommendMenus.get(person).contains(menu);
}

public void addMenu(Person person, String menu) {
recommendMenus.get(person).add(menu);
}

public Map<Person, List<String>> getRecommendMenus() {
return recommendMenus;
}
}
33 changes: 33 additions & 0 deletions src/main/java/menu/domain/RecommendationFoodCategories.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package menu.domain;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.ArrayList;
import java.util.List;

public class RecommendationFoodCategories {

private static final int MAX_CATEGORY_COUNT = 5;
private static final int MAX_CATEGORY_DUPLICATE = 2;

private final List<FoodCategory> recommendationFoodCategories;

public RecommendationFoodCategories() {
List<FoodCategory> categories = new ArrayList<>();
while (categories.size() < MAX_CATEGORY_COUNT) {
FoodCategory category = FoodCategory.from(
Randoms.pickNumberInRange(FoodCategory.getFirstNumber(), FoodCategory.getLastNumber()));
List<FoodCategory> foodCategories = categories.stream()
.filter(existingCategory -> existingCategory == category)
.toList();
if (foodCategories.size() < MAX_CATEGORY_DUPLICATE) {
categories.add(category);
}
}

this.recommendationFoodCategories = categories;
}

public List<FoodCategory> getRecommendationFoodCategories() {
return recommendationFoodCategories;
}
}
Loading