-
Notifications
You must be signed in to change notification settings - Fork 17
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
[BE] 김경규 오늘의 짝꿍은? #10
Open
KoungQ
wants to merge
13
commits into
Leets-Official:main
Choose a base branch
from
KoungQ:KoungQ
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
684f512
PR test
KoungQ c6e7b55
FEAT: 기능 완성
KoungQ fb7ebd0
FEAT: 출력 포멧 완성
KoungQ 3ce4826
REFACTOR: repeat 메서드 추출
KoungQ 182bfef
CHORE: 불필요한 주석 제거
KoungQ de1ac84
FIX: 잘못된 값 입력 시 다시 입력을 받도록 로직 수정
KoungQ b7f4eea
FIX: 메인 로직의 예외 위임 처리
KoungQ 3ed5e41
REFACTOR: 예외 위임 -> 메서드 내부에서 예외 처리
KoungQ 49e0872
REFACTOR: 스택 오버플로우 방지를 위해 재귀 -> 루프
KoungQ c99bb4f
CHORE: 메서드명, 주석 수정
KoungQ 9a8d0af
REFACTOR: 메서드 파라미터 수정
KoungQ 240ac0a
REFACTOR: 코드 리뷰 적용
KoungQ a2d3301
REFACTOR: Mockito를 이용한 테스트 코드 한정 BufferedReader 제어
KoungQ File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
188 changes: 173 additions & 15 deletions
188
src/main/java/leets/leets_mate/LeetsMateApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,200 @@ | ||
package leets.leets_mate; | ||
|
||
import leets.leets_mate.validation.exception.InvalidInputException; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.util.*; | ||
import java.util.regex.Pattern; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.IntStream; | ||
|
||
|
||
public class LeetsMateApplication { | ||
|
||
private static final int MAX_ERROR_COUNT = 5; // 최대 입력 횟수 | ||
private static final int INITIAL_ERROR_COUNT = 0; // 입력 횟수 세기 시작 | ||
private static final Pattern IS_KOREAN = Pattern.compile("^[ㄱ-ㅎㅏ-ㅣ가-힣]*$"); // regex 미리 컴파일 | ||
private static final Pattern IS_INTEGER = Pattern.compile("\\d+"); | ||
private BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); | ||
|
||
// 테스트 코드 실행을 위한 BufferedReader Setter | ||
public void setBufferedReader(BufferedReader br) { | ||
this.br = br; | ||
} | ||
|
||
public static void main(String[] args) { | ||
LeetsMateApplication app = new LeetsMateApplication(); | ||
app.run(); | ||
} | ||
|
||
// 동작 함수입니다. | ||
public void run() { | ||
/** 설계 | ||
* 1. 이름 입력 받기 | ||
* a. 입력 받기 (read) | ||
* b. String -> List (parseMember) | ||
* b. regex (checkHasNoEnglish) | ||
* 2. 최대 짝(그룹) 인원 수 입력 받기 | ||
* a. 총 멤버 수 계산 (memberNumber) | ||
* b. 입력 받기 (read) | ||
* c. int형으로 안전하게 변환 (convertToInteger) | ||
* d. '멤버 수 > 팀당 인원 수' 검사 (checkDataValidity) | ||
* e. 최대 짝(그룹) 인원 수 입력 받기 (getSize) | ||
* 3. 짝 랜덤 추첨 -> 출력 | ||
* a. 짝 추첨 실행 (executeDraw) | ||
* b, 짝 생성 (generateRandomGroups) | ||
* c. 결과 출력 (printResult) | ||
* d. 추첨을 멈출 것인지 결정 (isBreak) | ||
* | ||
* 예외) 사용자가 5번 이상 올바르지 않은 값을 입력할 시 프로그램 종료 | ||
*/ | ||
|
||
System.out.println(""" | ||
[Leets 오늘의 짝에게]를 시작합니다. | ||
|
||
멤버의 이름을 입력해주세요. (, 로 구분)"""); | ||
|
||
// 1. 이름 입력 받기 | ||
List<String> memberList = parseMembers(INITIAL_ERROR_COUNT); | ||
|
||
// 2. 인원 수 입력 받기 | ||
System.out.println("최대 짝 수를 입력해주세요."); | ||
int size = getSize(memberNumber(memberList), INITIAL_ERROR_COUNT); | ||
|
||
// 3. 짝 추첨 -> 출력 | ||
executeDraw(memberList, size); | ||
} | ||
|
||
// 문자열로된 멤버들을 리스트로 분리하는 함수입니다. | ||
public List<String> parseMembers(String members) { | ||
return new ArrayList<>(); | ||
public List<String> parseMembers(int errorCnt) { | ||
try { | ||
return Arrays.stream(read(errorCnt).split(",")) | ||
.peek(this::checkHasNoEnglish) // validation | ||
.collect(Collectors.toList()); | ||
} catch (InvalidInputException e) { | ||
System.out.println(e.getMessage()); | ||
return parseMembers(++errorCnt); | ||
} | ||
|
||
} | ||
|
||
// 총 멤버수를 반환합니다. | ||
public int memberNumber(List<String> members) { | ||
return 0; | ||
} | ||
|
||
// 멤버 문자열에 영어가 있는지 검사합니다. 영어가 있다면 예외 출력 | ||
public void checkHasNoEnglish(String members) { | ||
} | ||
|
||
// 멤버수와 최대 짝수 데이터가 유효한지 검사하는 함수입니다. 유효하지 않다면 예외 출력 | ||
public void checkDataValidity(int memberCount, int maximumGroupSize) { | ||
return members.size(); | ||
} | ||
|
||
// 랜덤 짝꿍 추첨하는 함수 입니다. | ||
public List<List<String>> generateRandomGroups(List<String> memberList, int maximumGroupSize) { | ||
return new ArrayList<>(); | ||
Collections.shuffle(memberList); // 리스트 셔플 | ||
|
||
int groupCnt = (int) Math.ceil((double) memberList.size() / maximumGroupSize); | ||
return IntStream.range(0, groupCnt) // 0 이상 그룹 개수 미만 범위 루프 | ||
.mapToObj(i -> memberList.subList(i * maximumGroupSize, | ||
Math.min((i + 1) * maximumGroupSize, memberList.size()) // 마지막 팀에 인원이 가득 차지 않았을 때 범위를 넘어가지 않기 위해 min 연산 | ||
)) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
// 결과를 프린트 하는 함수입니다. | ||
public void printResult(List<List<String>> result) { | ||
StringJoiner groupJoiner = new StringJoiner("\n"); | ||
for (List<String> group : result) { | ||
StringJoiner memberJoiner = new StringJoiner(" | ", "[ ", " ]"); | ||
for (String member : group) { | ||
memberJoiner.add(member); | ||
} | ||
groupJoiner.add(memberJoiner.toString()); | ||
} | ||
System.out.println(groupJoiner); | ||
} | ||
|
||
public static void main(String[] args) { | ||
LeetsMateApplication app = new LeetsMateApplication(); | ||
app.run(); | ||
// 원하는 결과가 나올 때까지 추첨을 진행하는 함수입니다. | ||
public void executeDraw(List<String> memberList, int size) throws InvalidInputException { | ||
System.out.println("\n오늘의 짝 추천 결과입니다."); | ||
|
||
List<List<String>> result = generateRandomGroups(memberList, size); // 짝 추첨 | ||
printResult(result); // 출력 | ||
System.out.println("추천을 완료했습니다."); | ||
|
||
if (!isBreak(INITIAL_ERROR_COUNT)) | ||
executeDraw(memberList, size); | ||
} | ||
|
||
// 추첨을 멈출 것인지 결정하는 함수입니다. | ||
public boolean isBreak(int errorCnt) { | ||
try { | ||
System.out.print("다시 구성하시겠습니까? (y or n): "); | ||
String input = read(errorCnt); | ||
|
||
if (input.equals("y")) { // 재구성 | ||
System.out.println("--------------------------------"); | ||
return false; | ||
} | ||
|
||
if (input.equals("n")) { // 고정 | ||
System.out.println("자리를 이동해 서로에게 인사해주세요."); | ||
return true; | ||
} | ||
|
||
// 그 외의 잘못된 응답 처리 | ||
throw new InvalidInputException("[ERROR] 응답은 y 혹은 n으로 입력해야 합니다."); | ||
} catch (InvalidInputException e) { | ||
System.out.println(e.getMessage()); | ||
return isBreak(++errorCnt); | ||
} | ||
} | ||
|
||
// 사용자의 모든 입력을 처리하는 함수입니다. | ||
public String read(int errorCnt) { | ||
try { | ||
if (errorCnt >= MAX_ERROR_COUNT) | ||
throw new InvalidInputException("[ERROR] 5회 이상 잘못 입력하셨습니다.\n프로그램을 종료합니다."); | ||
|
||
|
||
return Optional.of(br.readLine()) | ||
.filter(input -> !input.trim().isEmpty()) | ||
.orElseThrow(() -> new InvalidInputException("[ERROR] 값을 입력해주세요.")); // validation | ||
} catch (InvalidInputException e) { | ||
System.out.println(e.getMessage()); | ||
|
||
if (errorCnt >= MAX_ERROR_COUNT) | ||
System.exit(0); | ||
|
||
return read(++errorCnt); | ||
} catch (IOException e) { | ||
throw new RuntimeException("[ERROR] 입력을 읽는 중 오류가 발생했습니다.", e); | ||
} | ||
} | ||
|
||
// 그룹의 크기를 가져오는 함수입니다. | ||
public int getSize(int memberCnt, int errorCnt) { | ||
try { | ||
return checkDataValidity(memberCnt, convertToInteger(read(errorCnt))); | ||
} catch (InvalidInputException e) { | ||
System.out.println(e.getMessage()); | ||
return getSize(memberCnt, ++errorCnt); | ||
} | ||
} | ||
|
||
// validation | ||
public void checkHasNoEnglish(String members) throws InvalidInputException { | ||
if (!IS_KOREAN.matcher(members).matches()) | ||
throw new InvalidInputException("[ERROR] 이름은 공백없이 한글로 입력해야 합니다. 다시 입력해주세요."); | ||
} | ||
|
||
public int checkDataValidity(int memberCount, int maximumGroupSize) throws InvalidInputException { | ||
if (memberCount < maximumGroupSize) | ||
throw new InvalidInputException("[ERROR] 최대 짝 수는 이름의 갯수보다 클 수 없습니다. 다시 입력해주세요."); | ||
if (maximumGroupSize < 1) | ||
throw new InvalidInputException("[ERROR] 최대 짝 수는 1보다 작을 수 없습니다. 다시 입력해주세요."); | ||
return maximumGroupSize; | ||
} | ||
|
||
public int convertToInteger(String input) throws InvalidInputException { | ||
if (!IS_INTEGER.matcher(input).matches()) | ||
throw new InvalidInputException("[ERROR] 알맞은 짝의 크기를 입력해주세요."); | ||
return Integer.parseInt(input); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/leets/leets_mate/validation/exception/InvalidInputException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package leets.leets_mate.validation.exception; | ||
|
||
public class InvalidInputException extends RuntimeException { | ||
public InvalidInputException(String message) { | ||
super(message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
지금 코드도 좋지만, do~while문이 조건이 뒤에 있기때문에 가독성 면에서 안좋다는 의견도 있습니다.
때문에 아래와 같은 코드도 한번 보시면 좋을거 같습니다. while 없이 재귀로 해결하여 가독성은 좀 더 좋아질 수 있다 생각합니다.
`public void executeDraw(List memberList, int size) throws InvalidInputException {
System.out.println("\n오늘의 짝 추천 결과입니다.");
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.
초기엔 재귀로 코드를 짰었는데, 만약 사용자가 악의적으로 프로그램에 입력을 잘못 입력할 시엔 메모리가 계속 할당되어 스택 오버플로우가 발생할 수 있다는 생각도 했어서 넓은 의미로 루프문으로 고치게 되었습니다..!
근데 현재 상황은 그 정도까지 고려하는건 투머치라고 생각되네요.. 다음엔 문제 상황에 좀 더 알맞게 구성해보겠습니당 감사합니다!!
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.
저도 재귀로 사용했는데요! 스택오버플로를 고려하기도 했지만 현재는 오버엔지니어링이라 판단해 제한을 두지 않았습니다. 재귀로 사용한다면 tryCount를 두어 입력 횟수에 제한을 두는 것도 방법일 것 같아요!
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.
아하 역시나 투머치였군요..! 입력 횟수 제한 좋은 방법인 것 같아요 추가해보도록 하겠슴당 감사합니다!