-
Notifications
You must be signed in to change notification settings - Fork 50
[빙봉] 온보딩 코드리뷰 요청합니다. #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
Changes from all commits
0c4e779
c924385
c82d818
6806957
8a1e511
9ff5ba2
1b360a2
addb5c7
47cf992
3de7961
09addca
889a3c6
d1ea865
0b53410
c295110
750daac
a517723
8133b04
c2994fc
1576729
ba76416
b0881d4
11373d9
917bd64
21c17f3
187f90b
41209de
141f92b
838427e
7df937b
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,5 +1,18 @@ | ||
| # java-calculator | ||
| 문자열 계산기 미션 저장소 | ||
|
|
||
| ## 우아한테크코스 코드리뷰 | ||
| * [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md) | ||
| # 문자열 계산기 | ||
| | ||
| ## 요구사항 | ||
| | ||
| - 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다. | ||
| - 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다. | ||
| - 예를 들어 "2 + 3 * 4 / 2"와 같은 문자열을 입력할 경우 2 + 3 * 4 / 2 실행 결과인 10을 출력해야 한다. | ||
| | ||
| ## 추가할 기능 목록 | ||
| 1. 사용자로부터 입력받기 | ||
| 2. 홀수 인덱스와 짝수 인덱스로 나누는 함수 | ||
| 1. 짝수 인덱스일 때는 부호를 저장하는 로직 | ||
| 2. 홀수 인덱스일 경우에는 계산하는 함수 호출 | ||
| 3. 부호에 따라 계산하는 함수 구현 | ||
| 4. 사칙연산에 해당하는 각 함수 구현 | ||
| 5. 입력값을 확인하는 핸들러 구현 | ||
| 1. 양식에 맞지 않을 경우 (부호가 연속, 숫자가 연속으로 나올 경우) | ||
| 2. [예외 처리] 0으로 나눌 경우 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import calculator.domain.Calculator; | ||
|
|
||
| public class Application { | ||
| public static void main(String[] args){ | ||
| Calculator calculator = new Calculator(); | ||
| calculator.run(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| package calculator.domain; | ||
|
|
||
| import calculator.view.InputView; | ||
| import calculator.view.OutputView; | ||
|
|
||
| public class Calculator { | ||
| private static final int INDEX_INIT = 1; | ||
| private static final int FIRST_VALUE_INDEX = 0; | ||
| private static final int EVEN_NUMBER = 0; | ||
| private static final int ODD_NUMBER = 1; | ||
| private static final String DELIMITER = " "; | ||
| static double returnValue; | ||
| static String nowSign; | ||
|
|
||
| public void setNowSign(String sign) { | ||
| this.nowSign = sign; | ||
| } | ||
|
|
||
| public void setReturnValue(double returnValue) { | ||
| this.returnValue = returnValue; | ||
| } | ||
|
|
||
| public double getReturnValue() { | ||
| return this.returnValue; | ||
| } | ||
|
|
||
| public String getNowSign() { | ||
| return this.nowSign; | ||
| } | ||
|
|
||
| public static void run() { | ||
| String[] values = InputView.inputHandler().split(DELIMITER); | ||
| returnValue = Double.parseDouble(values[FIRST_VALUE_INDEX]); | ||
| selectOddNumberOrEvenNumber(values); | ||
| OutputView.printResult(returnValue); | ||
| } | ||
|
|
||
| public static void selectOddNumberOrEvenNumber(String[] values) { | ||
| for (int i = INDEX_INIT; i < values.length; i++) { | ||
| calculateEvenNumber(i, values[i]); | ||
| calculateOddNumber(i, values[i]); | ||
| } | ||
| } | ||
|
|
||
| public static boolean isOdd(int number) { | ||
| return number % 2 == ODD_NUMBER; | ||
| } | ||
|
|
||
| public static boolean isEven(int number) { | ||
| return number % 2 == EVEN_NUMBER; | ||
| } | ||
|
|
||
| public static void calculateOddNumber(int index, String value) { | ||
| if (isOdd(index)) { | ||
| nowSign = value; | ||
| } | ||
| } | ||
|
|
||
| public static void calculateEvenNumber(int index, String value) { | ||
| if (isEven(index)) { | ||
| selectOperators(Double.parseDouble(value)); | ||
| } | ||
| } | ||
|
|
||
| public static void selectOperators(double nowNumber) { | ||
| for (Operator operators : Operator.values()) { | ||
| calculateNumber(operators, nowNumber); | ||
| } | ||
| } | ||
|
|
||
| public static void calculateNumber(Operator operators, double nowNumber) { | ||
| if (operators.getOperator().equals(nowSign)) { | ||
| returnValue = operators.calculate(nowNumber, returnValue); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package calculator.domain; | ||
|
|
||
| import java.util.function.BiFunction; | ||
|
|
||
| public enum Operator { | ||
| PLUS("+", (nowNumber, returnValue) -> returnValue + nowNumber), | ||
| MINUS("-", (nowNumber, returnValue) -> returnValue - nowNumber), | ||
| MULTIPLY("*", (nowNumber, returnValue) -> returnValue * nowNumber), | ||
| DIVIDE("/", (nowNumber, returnValue) -> returnValue / nowNumber); | ||
|
Comment on lines
+6
to
+9
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. 👍 |
||
|
|
||
| private String operator; | ||
| private BiFunction<Double, Double, Double> expression; | ||
|
|
||
| Operator(String operator, BiFunction<Double, Double, Double> expression) { | ||
| this.operator = operator; | ||
| this.expression = expression; | ||
| } | ||
|
|
||
| public double calculate(double nowNumber, double returnValue) { | ||
| return expression.apply(nowNumber, returnValue); | ||
| } | ||
|
|
||
| public String getOperator() { | ||
| return this.operator; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package calculator.util; | ||
|
|
||
|
|
||
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.concurrent.atomic.AtomicInteger; | ||
|
|
||
| import static calculator.domain.Calculator.isEven; | ||
| import static calculator.domain.Calculator.isOdd; | ||
|
|
||
| public class ExceptionHandler { | ||
| private static final int EVEN = 0; | ||
| private static final String DELIMITER = " "; | ||
| private static final String BLANK = " "; | ||
| private static final String EMPTY_STRING = ""; | ||
| private static final String NUMBER_FORMAT = "-?\\d+(\\.\\d+)?"; | ||
| private static final String DIVIDE_ZERO_STRING = "/0"; | ||
| private static List<String> operatorList = Arrays.asList("+", "-", "*", "/"); | ||
|
|
||
| public static String checkInputHandler(String input) { | ||
| if (checkString(input.split(DELIMITER)) == true && checkUndefinedValue(input) == true) { | ||
|
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 안에 들어가는 조건식 메소드 명을 명시적으로 짓고, 따로 ture/false체크를 안하는 편입니다. 우테코 과정을 진행하면서 다른 분들과 의견을 나누어 보세요! |
||
| return input; | ||
| } | ||
| throw new IllegalArgumentException(); | ||
| } | ||
|
|
||
| public static boolean checkUndefinedValue(String str) { | ||
| if (str.replace(BLANK, EMPTY_STRING).contains(DIVIDE_ZERO_STRING)) { | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| public static boolean checkString(String[] inputStrings) { | ||
| if (inputStrings.length % 2 == EVEN) { | ||
| return false; | ||
| } | ||
|
|
||
| AtomicInteger index = new AtomicInteger(); | ||
| return Arrays.stream(inputStrings) | ||
| .allMatch(str -> checkIndividual(index.getAndIncrement(), str)); | ||
| } | ||
|
|
||
| public static boolean checkIndividual(int i, String inputString) { | ||
| if (isEven(i)) { | ||
| return checkNumber(inputString); | ||
| } | ||
| if (isOdd(i)) { | ||
| return checkSign(inputString); | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| public static boolean checkNumber(String inputString) { | ||
| return inputString.matches(NUMBER_FORMAT); | ||
| } | ||
|
|
||
| public static boolean checkSign(String inputString) { | ||
| if (operatorList.contains(inputString)) { | ||
| return true; | ||
| } | ||
| return false; | ||
|
Comment on lines
+58
to
+62
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,31 @@ | ||
| package calculator.view; | ||
|
|
||
| import java.util.InputMismatchException; | ||
| import java.util.Scanner; | ||
|
|
||
| import static calculator.util.ExceptionHandler.checkInputHandler; | ||
|
|
||
| public class InputView { | ||
|
|
||
| private static Scanner scanner = new Scanner(System.in); | ||
| private static final String INPUT_EXPRESSION_STR = "식을 입력해주세요 : "; | ||
| private static final String CHECK_INPUT_STR = "입력값을 확인해주세요!"; | ||
|
|
||
| public static String inputHandler() { | ||
| try { | ||
| return checkInputHandler(printInputExpression()); | ||
| } catch (InputMismatchException | IllegalArgumentException e) { | ||
| printInputCheck(); | ||
| return inputHandler(); | ||
| } | ||
| } | ||
|
|
||
| public static String printInputExpression(){ | ||
| System.out.print(INPUT_EXPRESSION_STR); | ||
| return scanner.nextLine(); | ||
| } | ||
|
|
||
| public static void printInputCheck(){ | ||
| System.out.println(CHECK_INPUT_STR); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package calculator.view; | ||
|
|
||
| public class OutputView { | ||
| public static void printResult(double result){ | ||
| String printFormat = "결과는 %f 입니다."; | ||
| if(result == Math.floor(result)){ | ||
| printFormat = "결과는 %.0f 입니다."; | ||
| } | ||
| System.out.printf(printFormat, result); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package calculator; | ||
|
|
||
| import calculator.domain.Calculator; | ||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.params.ParameterizedTest; | ||
| import org.junit.jupiter.params.provider.Arguments; | ||
| import org.junit.jupiter.params.provider.CsvSource; | ||
| import org.junit.jupiter.params.provider.MethodSource; | ||
|
|
||
| import java.util.stream.Stream; | ||
|
|
||
| import static calculator.domain.Calculator.*; | ||
| import static org.assertj.core.api.Assertions.*; | ||
|
|
||
| public class CalculatorTest { | ||
| static final double TEST_RETURN_VALUE_INIT = 10; | ||
| static final String TEST_NOW_SIGN_INIT = "+"; | ||
| Calculator calculator = new Calculator(); | ||
|
|
||
| @BeforeEach | ||
| void setUp() { | ||
| calculator.setReturnValue(TEST_RETURN_VALUE_INIT); | ||
| calculator.setNowSign(TEST_NOW_SIGN_INIT); | ||
| } | ||
|
|
||
| static Stream<Arguments> stringArrayProvider() { | ||
| return Stream.of( | ||
| Arguments.of(new String[]{"4", "*", "3", "/", "5", "-", "20"}, -17.6), | ||
| Arguments.of(new String[]{"2", "-", "1", "*", "3", "+", "2"}, 5) | ||
| ); | ||
| } | ||
|
|
||
| @ParameterizedTest | ||
| @MethodSource("stringArrayProvider") | ||
| @DisplayName("문자열을 받아 계산하는 메서드") | ||
| void selectOddNumberOrEvenNumberTest(String[] values, double expected) { | ||
| calculator.setReturnValue(Double.parseDouble(values[0])); | ||
| selectOddNumberOrEvenNumber(values); | ||
| assertThat(calculator.getReturnValue()).isEqualTo(expected); | ||
| } | ||
|
|
||
| @ParameterizedTest | ||
| @CsvSource(value = {"0:-:+", "1:*:*", "3:-:-"}, delimiter = ':') | ||
| @DisplayName("인덱스가 홀수면 부호를 저장하는 메서드") | ||
| void calculateOddNumberTest(int index, String value, String expected) { | ||
| calculator.calculateOddNumber(index, value); | ||
| assertThat(calculator.getNowSign()).isEqualTo(expected); | ||
| } | ||
|
|
||
| @ParameterizedTest | ||
| @CsvSource(value = {"0:1:11", "2:2.3:12.3", "3:4.0:10"}, delimiter = ':') | ||
| @DisplayName("인덱스가 짝수면 계산하는 메서드") | ||
| void calculateEvenNumberTest(int index, String value, double expected) { | ||
| calculator.calculateEvenNumber(index, value); | ||
| assertThat(calculator.getReturnValue()).isEqualTo(expected); | ||
| } | ||
|
|
||
| @ParameterizedTest | ||
| @CsvSource(value = {"1:11", "2.3:12.3", "4.0:14.0"}, delimiter = ':') | ||
| @DisplayName("연산자에 따라 계산하는 메서드") | ||
| void selectOperatorsTest(double value, double expected) { | ||
| calculator.selectOperators(value); | ||
| assertThat(calculator.getReturnValue()).isEqualTo(expected); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package calculator; | ||
|
|
||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.InputMismatchException; | ||
| import java.util.Scanner; | ||
| import java.util.concurrent.atomic.AtomicInteger; | ||
|
|
||
| import static calculator.util.ExceptionHandler.*; | ||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
|
||
| public class ExceptionHandlerTest { | ||
|
|
||
| @Test | ||
| @DisplayName("입력값을 체크해주는 테스트") | ||
| public void checkInputHandlerTest() { | ||
| String str = "321 + 3 + f"; | ||
| assertThatThrownBy(() -> { | ||
| checkInputHandler(str); | ||
| }).isInstanceOf(IllegalArgumentException.class); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("문자열을 split하고 전체적으로 체크해주는 테스트") | ||
| void checkStringTest() { | ||
| String[] inputStrings = "333 + 2434343".split(" "); | ||
| assertThat(checkString(inputStrings)).isTrue(); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("숫자인지 체크해주는 테스트") | ||
| void checkNumberTest() { | ||
| String str = "g"; | ||
| assertThat(checkNumber(str)).isFalse(); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("사칙연산인지 체크해주는 테스트") | ||
| void checkSignTest() { | ||
| String str = "@"; | ||
| assertThat(checkSign(str)).isFalse(); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("0으로 나누었을 때의 예외처리를 해주는 테스트") | ||
| void checkUndefinedValueTest() { | ||
| String str = "0 / 0"; | ||
| assertThat(checkUndefinedValue(str)).isFalse(); | ||
| } | ||
| } |
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.
👍