- 
                Notifications
    You must be signed in to change notification settings 
- Fork 155
[4기 - 황준호] 1~2주차 과제: 계산기 구현 미션 제출합니다. #191
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: juno-junho
Are you sure you want to change the base?
Changes from all commits
cef4f6a
              0e5168b
              8b786c2
              464ee7d
              d681ef6
              100652e
              a152c5f
              fcb46be
              cdb0b84
              747b790
              9c5d63c
              11f9b35
              daaabb9
              254d78b
              021662f
              07b941e
              f78d702
              04ecda0
              a01be32
              91358fc
              e80fbfc
              8b9fef4
              faacd78
              156e61b
              5034d14
              f8720b9
              ea769f0
              d7201e3
              eb3763d
              8e6ddbe
              1cb190f
              b1bc8a0
              1882786
              cab396b
              ae83531
              37fd625
              a610665
              c577dd7
              c3b3acc
              2b3fe4f
              2847dc7
              e0c42fa
              8568748
              bedc166
              1681a69
              f30f052
              7026a94
              c3469b0
              f022143
              bba7d3b
              fe6b642
              b2b4e92
              0a1bcd1
              49628f5
              c422b59
              c934956
              52b4812
              31d0c2b
              c2c482a
              7b07a10
              23f5a67
              3b4a132
              69bf844
              39d5517
              64b690d
              69bca5d
              f2064c9
              d5b9315
              552bdd3
              9df6088
              a425b61
              37b9706
              e1bb1da
              235f332
              06518a6
              665e715
              4e39667
              7e20296
              500eddf
              95d0f50
              07d518b
              64dae33
              73da710
              de9f0c1
              988d8f8
              0c6d27b
              c210056
              ff23b5e
              d8beb05
              9edbbd7
              038ad39
              3bd4249
              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,46 @@ | ||
| .gradle | ||
| build/ | ||
| !gradle/wrapper/gradle-wrapper.jar | ||
| !**/src/main/**/build/ | ||
| !**/src/test/**/build/ | ||
| gradlew.bat | ||
| gradlew | ||
| gradle | ||
|  | ||
| ### IntelliJ IDEA ### | ||
| .idea | ||
| .idea/modules.xml | ||
| .idea/jarRepositories.xml | ||
| .idea/compiler.xml | ||
| .idea/libraries/ | ||
| *.iws | ||
| *.iml | ||
| *.ipr | ||
| out/ | ||
| !**/src/main/**/out/ | ||
| !**/src/test/**/out/ | ||
|  | ||
| ### Eclipse ### | ||
| .apt_generated | ||
| .classpath | ||
| .factorypath | ||
| .project | ||
| .settings | ||
| .springBeans | ||
| .sts4-cache | ||
| bin/ | ||
| !**/src/main/**/bin/ | ||
| !**/src/test/**/bin/ | ||
|  | ||
| ### NetBeans ### | ||
| /nbproject/private/ | ||
| /nbbuild/ | ||
| /dist/ | ||
| /nbdist/ | ||
| /.nb-gradle/ | ||
|  | ||
| ### VS Code ### | ||
| .vscode/ | ||
|  | ||
| ### Mac OS ### | ||
| .DS_Store | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
|  | ||
| ## 자바 계산기 구현 미션 기능목록 작성 | ||
|  | ||
| 동작 예시 | ||
| ``` | ||
| 1. 조회 | ||
| 2. 계산 | ||
|  | ||
| 선택 : 2 | ||
|  | ||
| 1 + 2 | ||
| 3 | ||
|  | ||
| 1. 조회 | ||
| 2. 계산 | ||
|  | ||
| 선택 : 2 | ||
|  | ||
| 1 + 2 * 3 | ||
| 7 | ||
|  | ||
| 1. 조회 | ||
| 2. 계산 | ||
|  | ||
| 선택 : 1 | ||
|  | ||
| 1 + 2 = 3 | ||
| 1 + 2 * 3 = 7 | ||
|  | ||
| 선택 : 2 | ||
|  | ||
| 3 - 2 * 2 | ||
| -1 | ||
| ``` | ||
|  | ||
| - [x] 입력 | ||
| - [x] Scanner를 통한 콘솔 입력 | ||
| - [x] 선택 값 입력 받기 | ||
| - [x] 계산 기능 선택 시 -> 식 입력 받기 | ||
| - [x] BufferedReader로 입력 받는 것 교체 / 확장 가능 하게 추상화 시키기 (OCP) | ||
| - [x] 출력 | ||
| - [x] 조회 기능 선택 시 -> 조회 시 넘겨 받은 결과값 출력하기 | ||
| - [x] 계산 기능 선택 시 -> 계산 후 계산한 결과 출력하기 | ||
| - [x] OutputView 추상화 시키기 | ||
|  | ||
| - [x] 컨트롤러 및 application 생성 | ||
| - 컨트롤러 역할 : view와 domain을 이어 준다 / repository에서 값을 가져온다. | ||
| - 컨트롤러에서 담당 : repository를 결정한다 | ||
| - view는 주입 받는다(사용자가 결정) | ||
| - 게임을 실행하는 `run()`메서드를 가진다. | ||
| - Application 클래스 역할 : 사용자 | ||
| - 컨트롤러를 실행한다. | ||
| - view 객체를 생성해 컨트롤러에 주입시킨다. | ||
|  | ||
| - [x] 조회 기능 구현 | ||
| - [x] 조회시 계산한 값이 없으면 `계산 값이 존재하지 않습니다` 메세지 출력 -> OutputView에서 담당 | ||
| - [x] 계산 후 이력을 List로 저장 -> Repository에서 생성 | ||
| - [x] repository 패키지 안 List 가진 일급 컬렉션으로 구현 | ||
| - [x] 인터페이스로 repository 추상화 | ||
| - [x] 조회 기능 선택 시 계산 이력을 List에서 가져 오기 (repository에서 controller로 직접적으로 가져오기) | ||
|  | ||
|  | ||
| - [x] 계산 기능 구현 | ||
| - [x] 덧셈 | ||
| - [x] 뺄셈 | ||
| - [x] 나눗셈 | ||
| - [x] 곱하기 | ||
| - [x] 우선순위 (사칙연산) | ||
| - [x] 후위 표기식 찾아보기 | ||
| - [x] 나눗셈과 곱셈이 덧셈과 뺄셈보다 우선순위가 높다 | ||
| ``` | ||
| 중위 표현식 -> 후위 표현식 전환 알고리즘 : | ||
| 1. 피연산자는 스택에 넣지 않고 그냥 출력한다. | ||
| 2. 연산자는 스택이 비었으면 스택에 push한다. | ||
| 3. 연산자는 스택이 비어있지 않으면 스택에 있는 연산자와의 우선순위를 비교해 스택에 있는 연산자의 우선순위가 같거나 크다면 스택에 있는 연산자를 pop을 한 후 출력하고 현재 연산자는 스택에 push한다. | ||
| 4. 만약 3번에서 우선순위가 현재 연산자가 더 크면 현재 연산자를 push한다.(스택에서 pop하지 않음) | ||
| 5. 수식이 끝나면 스택이 빌 때 까지 pop을 한 후 출력한다. | ||
|  | ||
| 후위 표현식 -> 계산 알고리즘 | ||
| 1. 피연산자면 스택에 push한다. | ||
| 2. 연산자를 만나면 pop을 두번하고 각각 값을 저장한 후, 연산자에 맞는 계산을 한다. | ||
| 3. 계산을 한 뒤, 결과 값은 다시 스택에 넣는다. 이 과정을 수식이 끝날 때 까지 반복한다. | ||
| 4. 수식이 끝났다면 스택에 마지막 남은 값이 결과 값이 된다. | ||
| ``` | ||
| - [x] 식을 입력 받을 때 계산기에서 수행가능한 연산 범위를 제한 할 수 있다. | ||
| - [x] Regex를 통해서 검증하기. | ||
| - [x] 중위표현식, 후위 표현식에 따른 계산 확장 가능성 기능 구현 | ||
|  | ||
| - [x] 정규식 문제 해결 => \\ 추가해서 해설 | ||
| - [x] 0으로 나눌 경우 문제 해결 | ||
| - [x] var 사용 x -> 정확히 타입 표기를 통한 명시성 증가ㅈ | ||
|  | ||
| - [x] 예외 처리 | ||
| - [x] 조회(1), 계산(2) 이외의 값을 입력 했을 경우 `IllegalArgumentException` 발생 -> controller에서 처리 | ||
| - [x] 형식 (숫자 + 공백 + 기호 + 공백 + 숫자 + 공백 + 기호 + ...)이 잘못된 경우 `IllegalArgumentException` 발생 | ||
| - 공백은 무조건 하나로 처리 -> split시 space 하나로 처리해야 자를 수 있음. split 특성상 delimiter 포함 하지를 못한다. | ||
| - 정규식으로 처리 | ||
| - [x] 식에 int 형 범위 벗어 나 있는 경우 `IllegalArgumentException` 발생 | ||
| - [x] 계산 과정에 있어 int 자료형 overflow / underflow 발생 시 `IllegalArgumentException` 발생 | ||
| - Math 클래스의 `~Exact()` 메서드 사용 | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| plugins { | ||
| id 'java' | ||
| } | ||
|  | ||
| group = 'com.programmers' | ||
| version = '1.0-SNAPSHOT' | ||
|  | ||
| repositories { | ||
| mavenCentral() | ||
| } | ||
|  | ||
| dependencies { | ||
| testImplementation 'org.assertj:assertj-core:3.22.0' | ||
| testImplementation platform('org.junit:junit-bom:5.9.1') | ||
| testImplementation 'org.junit.jupiter:junit-jupiter' | ||
| } | ||
|  | ||
| test { | ||
| useJUnitPlatform() | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1 @@ | ||
| rootProject.name = 'java-calculator' | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.programmers.blackdog; | ||
|  | ||
| import com.programmers.blackdog.controller.CalculatorController; | ||
| import com.programmers.blackdog.view.*; | ||
|  | ||
| public class Application { | ||
| public static void main(String[] args) { | ||
| InputView inputView = new ScannerInputView(); | ||
| OutputView outputView = new PrintStreamOutputView(); | ||
| Console console = new Console(inputView, outputView); | ||
|  | ||
| CalculatorController calculator = new CalculatorController(console); | ||
| calculator.run(); | ||
| } | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package com.programmers.blackdog.controller; | ||
|  | ||
| import com.programmers.blackdog.controller.constant.Selection; | ||
| import com.programmers.blackdog.service.CalculatorService; | ||
| import com.programmers.blackdog.service.Service; | ||
| import com.programmers.blackdog.view.Console; | ||
|  | ||
| import java.util.List; | ||
|  | ||
| import static com.programmers.blackdog.controller.constant.Selection.findByCode; | ||
|  | ||
| public class CalculatorController { | ||
|  | ||
| private final Service service; | ||
| private final Console console; | ||
|  | ||
| public CalculatorController(Console console) { | ||
| this.console = console; | ||
| this.service = new CalculatorService(); | ||
| 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는 왜 주입을 안받고 직접 생성하시는지 이유가 궁금합니다. | ||
| } | ||
|  | ||
| public void run() { | ||
| while (true) { | ||
| try { | ||
| switch (getCode()) { | ||
| case CHECK_DATA: | ||
| printAllPreviousData(); | ||
| break; | ||
| case CALCULATE: | ||
| printCalculatedResultAndSave(); | ||
| break; | ||
| case EXIT: | ||
| exitProgram(); | ||
| return; | ||
| } | ||
| } catch (Exception e) { | ||
| 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. 혹시 왜 매우 넓은 범위의 Exception을 통째로 catch하신지 이유가 궁금합니다. | ||
| console.printErrorMessage(e.getMessage()); | ||
| } | ||
| } | ||
| } | ||
|  | ||
| private Selection getCode() { | ||
| 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. getCode() 보다는 조금더 명확한 의미가 좋을거같아요. 일반적으로 저는 get을 프로퍼티나 필드의 값을 가져올때 사용합니다. 사용자로부터 입력을 받아온다면? | ||
| int selectionCode = console.getSelectionCode(); | ||
| return findByCode(selectionCode); | ||
| } | ||
|  | ||
|  | ||
| private void printAllPreviousData() { | ||
| List<String> calculatedData = service.findAll(); | ||
| console.printExpressions(calculatedData); | ||
| } | ||
| 
      Comment on lines
    
      +48
     to 
      +51
    
   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. 지역변수명도 동일합니당 | ||
|  | ||
| private void printCalculatedResultAndSave() { | ||
| String expression = console.getExpression(); | ||
| int result = service.calculate(expression); | ||
|  | ||
| service.save(expression, result); | ||
|  | ||
| console.printCalculatedResult(result); | ||
| } | ||
|  | ||
| private void exitProgram() { | ||
| console.printEndMessage(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package com.programmers.blackdog.controller.constant; | ||
|  | ||
| import java.util.Arrays; | ||
|  | ||
| public enum Selection { | ||
| CHECK_DATA(1), CALCULATE(2), EXIT(3); | ||
|  | ||
| private final int code; | ||
|  | ||
| Selection(int code) { | ||
| this.code = code; | ||
| } | ||
|  | ||
| public static Selection findByCode(int code) { | ||
| return Arrays.stream(Selection.values()) | ||
| .filter(selection -> selection.code == code) | ||
| .findAny() | ||
| .orElseThrow(() -> new IllegalArgumentException("해당 값이 없습니다")); | ||
| 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,63 @@ | ||
| package com.programmers.blackdog.domain; | ||
|  | ||
| import java.util.Arrays; | ||
|  | ||
| public enum ArithmeticOperators implements Operable { | ||
| ADDITION("+", 0) { | ||
| @Override | ||
| public int apply(int a, int b) { | ||
| return Math.addExact(a, b); | ||
| } | ||
| }, SUBTRACTION("-", 0) { | ||
| @Override | ||
| public int apply(int a, int b) { | ||
| return Math.subtractExact(a, b); | ||
| } | ||
| }, MULTIPLICATION("*", 1) { | ||
| @Override | ||
| public int apply(int a, int b) { | ||
| return Math.multiplyExact(a, b); | ||
| } | ||
| }, DIVISION("/", 1) { | ||
| @Override | ||
| public int apply(int a, int b) { | ||
| validateDivideNumIsZero(b); | ||
| return a / b; | ||
| } | ||
| }; | ||
|  | ||
| private static void validateDivideNumIsZero(int num) { | ||
| if (num == 0) { | ||
| throw new ArithmeticException("0으로 나눌 수 없습니다."); | ||
| } | ||
| } | ||
|  | ||
| private final String operator; | ||
| private final int priority; | ||
|  | ||
| ArithmeticOperators(String operator, int priority) { | ||
| this.operator = operator; | ||
| this.priority = priority; | ||
|  | ||
| 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 static ArithmeticOperators convertTokenToOperator(String token) { | ||
| return Arrays.stream(values()) | ||
| .filter(operator -> operator.getOperator().equals(token)) | ||
| .findAny() | ||
| .orElseThrow(); | ||
| 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 static boolean isNotOperator(String token) { | ||
| return Arrays.stream(values()) | ||
| .noneMatch(operator -> operator.getOperator().equals(token)); | ||
| } | ||
|  | ||
| public String getOperator() { | ||
| return operator; | ||
| } | ||
|  | ||
| public int getPriority() { | ||
| return priority; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package com.programmers.blackdog.domain; | ||
|  | ||
| @FunctionalInterface | ||
| public interface Operable { | ||
| 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. good int만 지원되는건 아쉽네요. 다른 방법이 있지 않을까요? 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. i think so too. | ||
| int apply(int a, int b); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package com.programmers.blackdog.domain; | ||
|  | ||
| import java.util.Arrays; | ||
| import java.util.stream.Collectors; | ||
|  | ||
| import static com.programmers.blackdog.domain.ArithmeticOperators.values; | ||
|  | ||
| public class RegexGenerator { | ||
| 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 static final String REGEX_PREFIX = "^\\d+\\s(["; | ||
| private static final String REGEX_SUFFIX = "]\\s\\d+\\s)+$"; | ||
| public static final String PREFIX = "\\"; | ||
| public static final String SUFFIX = ""; | ||
|  | ||
| public String generateWithOperator(ArithmeticOperators... arithmeticOperators) { | ||
| 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. ArithmeticOperators... 는 동작할 때 어떤 차이가 있을까요? | ||
| StringBuilder operators = new StringBuilder(); | ||
| for (ArithmeticOperators arithmeticOperator : arithmeticOperators) { | ||
| operators.append(PREFIX).append(arithmeticOperator.getOperator()); | ||
| } | ||
| return REGEX_PREFIX + operators.append(REGEX_SUFFIX); | ||
| } | ||
|  | ||
| public String generateWithAllOperator() { | ||
| String allOperators = Arrays.stream(values()) | ||
| .map(ArithmeticOperators::getOperator) | ||
| .collect(Collectors.joining(PREFIX, PREFIX, SUFFIX)); | ||
| return REGEX_PREFIX + allOperators + REGEX_SUFFIX; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.programmers.blackdog.domain.calculator; | ||
|  | ||
| import com.programmers.blackdog.domain.expression.Expression; | ||
|  | ||
| public interface AbstractCalculator { | ||
| int calculate(Expression expression); | ||
| 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. 계산 결과가 int만 지원되는건 아쉽네요! 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. 계산 결과가 단순 int value로 리턴되기보다 객체로 바라볼 순 없을까요? | ||
| } | ||
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.
MVC 패턴과 Layered 아키텍처로 설계하신거 같아요!
Controller는 어떤 역할을 할까요? 준호님의 생각이 궁금합니다.