-
Notifications
You must be signed in to change notification settings - Fork 9
[문자열 계산기] 김난슬 미션 제출합니다. #8
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
base: main
Are you sure you want to change the base?
Changes from all commits
502ca47
64d3c5f
4c04182
687dc06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,34 @@ | ||
| # java-calculator-precourse | ||
| # java-calculator-precourse | ||
|
|
||
| ## 기능 요구 사항 | ||
|
|
||
| --- | ||
|
|
||
| 입력한 문자열에서 숫자를 추출하여 더하는 계산기를 구현한다. | ||
|
|
||
| - 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환한다. | ||
| - 예: "" => 0, "1,2" => 3, "1,2,3" => 6, "1,2:3" => 6 | ||
| - 앞의 기본 구분자(쉼표, 콜론) 외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 "//"와 "\n" 사이에 위치하는 문자를 커스텀 구분자로 사용한다. | ||
| - 예를 들어 "//;\n1;2;3"과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다. | ||
| - 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다. | ||
|
|
||
| ## 프로그래밍 요구사항 | ||
|
|
||
| --- | ||
|
|
||
| ### Java | ||
|
|
||
| - JDK 21 버전에서 실행 가능해야 한다. | ||
| - 프로그램 실행의 시작점은 `Application`의 `main()` 이다. | ||
| - `build.gradle` 파일은 변경할 수 없으며, **제공된 라이브러리 이외의 외부 라이브러리는 사용하지 않는다.** | ||
| - 프로그램 종료 시 `System.exit()`를 호출하지 않는다. | ||
| - 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 등의 이름을 바꾸거나 이동하지 않는다. | ||
| - 자바 코드 컨벤션을 지키면서 프로그래밍한다. | ||
| - 기본적으로 Java Style Guide(https://github.com/woowacourse/woowacourse-docs/tree/main/styleguide/java)를 원칙으로 한다. | ||
|
|
||
| ### 라이브러리 | ||
|
|
||
| ### Java | ||
|
|
||
| - `camp.nextstep.edu.missionutils`에서 제공하는 `Console` API를 사용하여 구현해야 한다. | ||
| - 사용자가 입력하는 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용한다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,10 @@ | ||
| package calculator; | ||
|
|
||
| import calculator.controller.CalculatorController; | ||
|
|
||
| public class Application { | ||
| public static void main(String[] args) { | ||
| // TODO: 프로그램 구현 | ||
| CalculatorController controller = new CalculatorController(); | ||
| controller.startCalculator(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package calculator.controller; | ||
|
|
||
| import calculator.model.Calculator; | ||
| import calculator.view.InputView; | ||
| import calculator.view.OutputView; | ||
|
|
||
| public class CalculatorController { | ||
| public void startCalculator() { | ||
| try { | ||
| String input = InputView.getInput(); | ||
| int result = Calculator.processSum(input); | ||
| OutputView.printResult(result); | ||
| } catch (IllegalArgumentException e) { | ||
| OutputView.printError(e.getMessage()); | ||
| throw e; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package calculator.model; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 덕분에 좋은 라이브러리들 알아갑니다 |
||
| public class Calculator { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필드가 없고 기능만 있다면 모델 보다는 service나 utils로 취급되는게 더 적절해보여요! |
||
| public static int processSum(String numbers) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 메서드가 갖고있는 책임이 너무 큰 것 같습니다. 구분자를 확인 및 설정하는 것, 예외를 처리하는 것, 계산하는 것 등 세부 기능으로 메서드를 만들어 분리하는 쪽이 더 좋지 않을까요? |
||
| if (numbers == null || numbers.trim().isEmpty()) { | ||
| return 0; | ||
| } | ||
|
|
||
| List<String> delimiters = Arrays.asList(",", ":"); | ||
|
|
||
| Matcher matcher = Pattern.compile("^//(.)\\\\n(.*)").matcher(numbers); | ||
|
|
||
| if (matcher.find()) { | ||
| String customDelimiter = Pattern.quote(matcher.group(1)); | ||
| delimiters = Arrays.asList(customDelimiter, ",", ":"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. delimiter 필드를 재정의할 필요가 있을까요? List로 둔다면 ArrayList 내지는 LinkedList 등으로 두고 원소를 추가하는 편이 더 직관적으로 와닿을 것 같아요! There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. 동의합니다.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. 저도 추가하는 편이 더 좋은 것 같습니다! |
||
| numbers = matcher.group(2); | ||
| } | ||
|
|
||
| if (numbers.trim().isEmpty()) { | ||
| throw new IllegalArgumentException("커스텀 구분자 이후 숫자가 없습니다."); | ||
| } | ||
|
|
||
| String delimiterRegex = String.join("|", delimiters); | ||
|
|
||
| return Arrays.stream(numbers.split(delimiterRegex)) | ||
| .map(String::trim) | ||
| .filter(num -> !num.isEmpty()) | ||
| .mapToInt(Calculator::parseValidation) | ||
| .sum(); | ||
| } | ||
|
|
||
| private static int parseValidation(String num) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 밑에서 변환 예외와 음수 예외를 다루는데 제가 받아들이기에는 역할이 2개여서 가독성이 떨어지는 것 같아요. 개인적인 생각으로는 검증 역시 메서드를 나눠도 좋을 것 같아요.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. 어떠한 기능만 수행해서 return해주는 메서드의 파라미터는 첫 글자만 남겨서 네이밍해도 괜찮을 것 같아요.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제안해주신 방식도 간결한 코드에서 효과적일 수 있다고도 생각합니다. 다만, 네이밍이 짧아지면 가독성이 떨어지고 유지보수할 때 혼란이 될 수도 있다고 생각해서요 그래도 현록님이 이 방식이 더 괜찮다고 생각하시는 이유가 있을까용? 생각하시는 더 좋은 규칙이 있다면 같이 얘기해보고싶어요! @Regyung |
||
| try { | ||
| int value = Integer.parseInt(num); | ||
| if (value < 0) { | ||
| throw new IllegalArgumentException("음수는 입력할 수 없습니다: " + num); | ||
| } | ||
| return value; | ||
| } catch (NumberFormatException e) { | ||
| throw new IllegalArgumentException("잘못된 숫자 입력: " + num); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package calculator.view; | ||
|
|
||
| import camp.nextstep.edu.missionutils.Console; | ||
|
|
||
| public class InputView { | ||
| public static String getInput() { | ||
| System.out.print("문자열을 입력하세요 :"); | ||
| String userInputValue = Console.readLine(); | ||
|
|
||
| return userInputValue; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package calculator.view; | ||
|
|
||
| public class OutputView { | ||
| public static void printResult(int result) { | ||
| System.out.println("결과 : " + result); | ||
| } | ||
| public static void printError(String message) { | ||
| System.out.println("오류 발생 : " + message); | ||
|
seulnan marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 같은 생각입니다! |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package calculator; | ||
|
|
||
| import calculator.model.Calculator; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 케이스를 공부하게 되었습니다 이렇게 쓰는거였군요 |
||
|
|
||
| class BasicCalculatorTest { // ✅ 더 명확한 이름으로 변경 | ||
|
|
||
| @Test | ||
| void 빈문자열_테스트() { | ||
| assertThat(Calculator.processSum("")).isEqualTo(0); | ||
| } | ||
|
|
||
| @Test | ||
| void 기본_구분자_테스트() { | ||
| assertThat(Calculator.processSum("1,2:3")).isEqualTo(6); | ||
| } | ||
|
|
||
| @Test | ||
| void 하나의_숫자만_입력() { | ||
| assertThat(Calculator.processSum("5")).isEqualTo(5); | ||
| } | ||
|
|
||
| } | ||
|
seulnan marked this conversation as resolved.
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 문자열 중간에 커스텀 구분자를 추가할 순 없을까요?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 혹시 경수님께서 중간에 커스텀 구분자를 허용해야 한다고 생각하신다면, 어떤 요구사항을 기준으로 고려하셨는지 의견을 나눠보면 좋을 것 같아요! @Siul49 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package calculator; | ||
|
|
||
| import calculator.model.Calculator; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
| public class CustomCalculatorTest { | ||
| @Test | ||
| void 기본_구분자_테스트() { | ||
| assertThat(Calculator.processSum("1,2:3")).isEqualTo(6); | ||
| } | ||
|
|
||
| @Test | ||
| void 커스텀_구분자_테스트() { | ||
| assertThat(Calculator.processSum("//;\\n1;2;3")).isEqualTo(6); | ||
| } | ||
|
|
||
| @Test | ||
| void 기본_구분자_혼합사용_테스트() { | ||
| assertThat(Calculator.processSum("//;\\n1;2,3:4")).isEqualTo(10); | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 나중에 생각난 것이지만 커스텀 구분자가 2개 이상일 수도 있을 상황이 존재할 것도 같습니다!
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
컨트롤러에서 뷰와 모델을 static call을 하는 이유가 있나요?
특별한 이유가 없다면 의존성을 생각해서 DI를 하는게 더 낫지 않을까요?
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.
아하 그 방향대로 수정해보겠습니다!