- 
                Notifications
    You must be signed in to change notification settings 
- Fork 155
[4기 - 한승원] 1~2주차 과제 : 계산기 구현 미션 제출합니다(사칙연산) #168
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: seungwon
Are you sure you want to change the base?
Changes from 11 commits
2f8bb46
              5a6deed
              c4c3e88
              e2dcb42
              bd3aee3
              52a1300
              ee4d032
              842467d
              c9c80e0
              25a513e
              6d94091
              4d764ca
              882c684
              1a150a5
              a3901a5
              451742e
              775466d
              5e41f40
              2590e8c
              6b66bc0
              2f88ba9
              f154103
              ddc919c
              9b34581
              9b943b9
              c6c5a68
              6d43a13
              97b393a
              84540a2
              eeb3796
              c37cdad
              50cabb1
              0ac007e
              8b4ec3a
              a3544d8
              ea158fe
              6f1519d
              7fe46d5
              aa52739
              202ce5d
              716fb12
              c2351bd
              1f42c10
              358117c
              f635ecb
              06b76d3
              84ff197
              49675ef
              62afa70
              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 | 
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package co.programmers.application; | ||
|  | ||
| import co.programmers.view.CalculatorInputView; | ||
| import co.programmers.view.CalculatorOutputView; | ||
| import co.programmers.view.InputView; | ||
| import co.programmers.view.OutputView; | ||
|  | ||
| public class Application { | ||
|  | ||
| public static void main(String[] args) { | ||
| InputView inputView = new CalculatorInputView(); | ||
| OutputView outputView = new CalculatorOutputView(); | ||
| Calculator calculator = new Calculator(inputView, outputView); | ||
| calculator.run(); | ||
| } | ||
| } | ||
|          | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| package co.programmers.application; | ||
|  | ||
| import co.programmers.domain.Operator; | ||
| import co.programmers.domain.UserMenu; | ||
| import co.programmers.view.InputView; | ||
| import co.programmers.view.OutputView; | ||
| import java.util.Stack; | ||
|  | ||
| public class Calculator { | ||
|  | ||
| private final InputView inputView; | ||
| private final OutputView outputView; | ||
|  | ||
| public Calculator(InputView inputView, OutputView outputView) { | ||
| this.inputView = inputView; | ||
| this.outputView = outputView; | ||
| } | ||
|  | ||
| public void run() { | ||
| while (true) { | ||
|          | ||
| UserMenu userMenu = UserMenu.get(inputView.inputUserMenu()); | ||
| switch (userMenu) { | ||
| case INQUIRY: | ||
| // 구현 예정 | ||
| break; | ||
| case CALCULATE: | ||
| String expression = inputView.inputExpression(); | ||
| Integer output = calculate(expression); | ||
| outputView.print(String.valueOf(output)); | ||
|          | ||
| break; | ||
| case TERMINATE: | ||
| return; | ||
| } | ||
| } | ||
| } | ||
|  | ||
| private Integer calculate(String input) { | ||
| char[] expression = input.toCharArray(); | ||
|          | ||
| Stack<Integer> Operands = new Stack<>(); | ||
| Stack<Character> Operators = new Stack<>(); | ||
|          | ||
| for (int i = 0; i < expression.length; i++) { | ||
| if (Character.isWhitespace(expression[i])) { | ||
| continue; | ||
| } | ||
| if (Character.isDigit(expression[i])) { | ||
| StringBuffer operand = new StringBuffer(); | ||
| while (i < expression.length && Character.isDigit(expression[i])) { | ||
| operand.append(expression[i++]); | ||
| } | ||
| i--; | ||
| Operands.push(Integer.parseInt(operand.toString())); | ||
| } else if (expression[i] == '(') { | ||
| Operators.push(expression[i]); | ||
| } else if (expression[i] == ')') { | ||
| evaluateOperators(Operands, Operators); | ||
|          | ||
| } else { | ||
| while (!Operators.empty() && comparePriority(expression[i], Operators.peek())) { | ||
| Operands.push(Operator.calculate( | ||
| String.valueOf(Operators.pop()), Operands.pop(), Operands.pop() | ||
| )); | ||
| } | ||
| Operators.push(expression[i]); | ||
| } | ||
|          | ||
| } | ||
|          | ||
| evaluateOperators(Operands, Operators); | ||
| return Operands.pop(); | ||
| } | ||
|  | ||
| private void evaluateOperators(Stack<Integer> operands, Stack<Character> operators) { | ||
| while (!operators.empty() && (operators.peek() != '(')) { | ||
| Character operator = operators.pop(); | ||
| Integer operand1 = operands.pop(); | ||
| Integer operand2 = operands.pop(); | ||
| int result = Operator.calculate( | ||
| String.valueOf(operator), operand1, operand2 | ||
| ); | ||
| operands.push(result); | ||
| } | ||
|  | ||
| if (!operators.empty()) { | ||
| operators.pop(); | ||
| } | ||
| } | ||
|  | ||
| private boolean comparePriority(char operator1, char operator2) { | ||
| return Operator.getSymbol(String.valueOf(operator1)).getPriority() >= | ||
| Operator.getSymbol(String.valueOf(operator2)).getPriority(); | ||
|          | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,60 @@ | ||||||||||||||||||||||
| package co.programmers.domain; | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| import co.programmers.exception.ExceptionMessage; | ||||||||||||||||||||||
| import java.util.Collections; | ||||||||||||||||||||||
| import java.util.Map; | ||||||||||||||||||||||
| import java.util.Optional; | ||||||||||||||||||||||
| import java.util.function.BiFunction; | ||||||||||||||||||||||
| import java.util.function.Function; | ||||||||||||||||||||||
| import java.util.stream.Collectors; | ||||||||||||||||||||||
| import java.util.stream.Stream; | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| public enum Operator { | ||||||||||||||||||||||
| ADDITION("+", 2, (operand1, operand2) -> Integer.valueOf( | ||||||||||||||||||||||
| operand1 + operand2 | ||||||||||||||||||||||
| )), | ||||||||||||||||||||||
| SUBTRACTION("-", 2, (operand1, operand2) -> Integer.valueOf( | ||||||||||||||||||||||
| operand2 - operand1 | ||||||||||||||||||||||
|          | ||||||||||||||||||||||
| )), | ||||||||||||||||||||||
| MULTIPLICATION("*", 1, (operand1, operand2) -> Integer.valueOf( | ||||||||||||||||||||||
| operand1 * operand2 | ||||||||||||||||||||||
| )), | ||||||||||||||||||||||
| DIVISION("/", 1, (operand1, operand2) -> { | ||||||||||||||||||||||
| if (operand2 == 0) { | ||||||||||||||||||||||
| throw new IllegalArgumentException(ExceptionMessage.DIVIDED_BY_ZERO); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| return Integer.valueOf(operand1 / operand2); | ||||||||||||||||||||||
| }), | ||||||||||||||||||||||
| OPENED_PARENTHESIS("(", 3, (operand1, operand2) -> 0), | ||||||||||||||||||||||
| CLOSED_PARENTHESIS(")", 3, (operand1, operand2) -> 0); | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| private static final Map<String, Operator> operators = | ||||||||||||||||||||||
| Collections.unmodifiableMap(Stream.of(values()) | ||||||||||||||||||||||
| .collect(Collectors.toMap(Operator::getSymbol, Function.identity()))); | ||||||||||||||||||||||
|          | ||||||||||||||||||||||
| private final String symbol; | ||||||||||||||||||||||
| private final int priority; | ||||||||||||||||||||||
| private final BiFunction<Integer, Integer, Integer> operation; | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| Operator(String symbol, int priority, BiFunction<Integer, Integer, Integer> operation) { | ||||||||||||||||||||||
| this.symbol = symbol; | ||||||||||||||||||||||
| this.priority = priority; | ||||||||||||||||||||||
| this.operation = operation; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| public static Integer calculate(String operator, Integer operand1, Integer operand2) { | ||||||||||||||||||||||
| return getSymbol(operator).operation.apply(operand1, operand2); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| public static Operator getSymbol(String operator) { | ||||||||||||||||||||||
| return Optional.ofNullable(operators.get(operator)) | ||||||||||||||||||||||
| .orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.INVALID_SYMBOL)); | ||||||||||||||||||||||
|          | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|          | ||||||||||||||||||||||
| public static Operator getSymbol(String operator) { | |
| return Optional.ofNullable(operators.get(operator)) | |
| .orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.INVALID_SYMBOL)); | |
| } | |
| public static Operator getOperator(String input) { | |
| return Arrays.stream(Operator.values()) | |
| .filter(operator -> operator.symbol.equals(input)) | |
| .findFirst() | |
| .orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.INVALID_SYMBOL)); | |
| } | 
이런 방법은 어떠신가요?
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package co.programmers.domain; | ||
|  | ||
| import java.util.Collections; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import java.util.function.Function; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.Stream; | ||
|  | ||
| public enum UserMenu { | ||
| INQUIRY("1"), | ||
| CALCULATE("2"), | ||
| TERMINATE("3"); | ||
|  | ||
| private static final Map<String, UserMenu> values = | ||
| Collections.unmodifiableMap(Stream.of(values()) | ||
| .collect(Collectors.toMap(UserMenu::getValue, Function.identity()))); | ||
|          | ||
| private final String value; | ||
|  | ||
| UserMenu(String value) { | ||
| this.value = value; | ||
| } | ||
|  | ||
| public static UserMenu get(String input) { | ||
| return Optional.ofNullable(values.get(input)).orElse(TERMINATE); | ||
| } | ||
|          | ||
|  | ||
| public String getValue() { | ||
| return value; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package co.programmers.exception; | ||
|  | ||
| public class ExceptionMessage { | ||
|  | ||
| public static final String DIVIDED_BY_ZERO = "0으로 나눌 수 없습니다."; | ||
| public static final String INVALID_SYMBOL = "잘못된 연산 기호입니다."; | ||
| public static final String INVALID_INPUT = "잘못된 입력입니다"; | ||
|  | ||
| private ExceptionMessage() { | ||
| } | ||
| } | ||
|          | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| package co.programmers.view; | ||
|  | ||
| import co.programmers.exception.ExceptionMessage; | ||
| import co.programmers.domain.UserMenu; | ||
| import java.util.Arrays; | ||
| import java.util.Scanner; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
|  | ||
| public class CalculatorInputView implements InputView { | ||
|  | ||
| private static final Scanner SCANNER = new Scanner(System.in); | ||
| private static final Set<String> USER_MENU = | ||
| Arrays.stream(UserMenu.values()) | ||
| .map(UserMenu::getValue) | ||
| .collect(Collectors.toSet()); | ||
|          | ||
|  | ||
| public CalculatorInputView() { | ||
| } | ||
|          | ||
|  | ||
| public String inputUserMenu() { | ||
| printMenuChoiceGuide(); | ||
| String userInput = SCANNER.next(); | ||
| SCANNER.nextLine(); | ||
| try { | ||
| validateUserMenuChoice(String.valueOf(userInput)); | ||
| } catch (IllegalArgumentException illegalArgumentException) { | ||
| System.out.println(illegalArgumentException.getMessage()); | ||
| return UserMenu.TERMINATE.getValue(); | ||
|          | ||
| } | ||
| return userInput; | ||
| } | ||
|  | ||
| public String inputExpression() { | ||
| printCalculationGuide(); | ||
| String expression = SCANNER.nextLine(); | ||
| return expression; | ||
| } | ||
|  | ||
| private void printCalculationGuide() { | ||
| System.out.println("1 + 2 * 3와 같은 형식으로 계산하고자 하는 식을 입력하세요."); | ||
| System.out.print("> "); | ||
| } | ||
|  | ||
| private void printMenuChoiceGuide() { | ||
| System.out.println("\n[다음 중 원하시는 항목을 숫자로 입력하세요]"); | ||
| System.out.println("1. 조회"); | ||
| System.out.println("2. 계산"); | ||
| System.out.println("3. 종료"); | ||
| System.out.print("> 선택 : "); | ||
| } | ||
|          | ||
|  | ||
| private void validateUserMenuChoice(String userInput) throws IllegalArgumentException { | ||
| if (!USER_MENU.contains(userInput)) { | ||
| throw new IllegalArgumentException(ExceptionMessage.INVALID_INPUT); | ||
| } | ||
| } | ||
|          | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package co.programmers.view; | ||
|  | ||
| public class CalculatorOutputView implements OutputView { | ||
|  | ||
| public void print(String content) { | ||
| System.out.println(">> 결과 : " + content); | ||
| } | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package co.programmers.view; | ||
|  | ||
| public interface InputView { | ||
|  | ||
| String inputUserMenu(); | ||
|  | ||
| String inputExpression(); | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package co.programmers.view; | ||
|  | ||
| public interface OutputView { | ||
|  | ||
| void print(String content); | ||
|  | ||
| } | 
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.
👍