-
Notifications
You must be signed in to change notification settings - Fork 156
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
[4기 - 전선희] 1~2주차 과제 : 계산기 구현 미션 제출합니다. (2차) #172
base: funnysunny08
Are you sure you want to change the base?
Conversation
case 1 -> result.readAllResults(); | ||
case 2 -> result.save(bc.doCalculate(input.getExpression())); | ||
case 3 -> isExecutable = false; | ||
Menu menu = Menu.matchMenu(input.selectMenu()); |
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.
한줄로 쭉 쓰시면 input.selectMenu()
값을 디버깅하고 확인하기 어려울 것 같아요!
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.
matchMenu
라는 메서드의 동사는 match
인데 이건 일치하는 지 확인하는 함수처럼 보여서 boolean 값을 반환할 거 같아요. 정적 팩토리 메서드 네이밍을 찾아보시고 참고하시면 좋을 것 같아요.
switch (menu) { | ||
case LOOK_UP -> output.readAllResults(resultManager.readAllResults()); | ||
case CALCULATE -> calculate(); | ||
case EXIT -> { | ||
return; | ||
} | ||
default -> output.inputError(); | ||
} | ||
} | ||
} | ||
|
||
private void calculate() { | ||
String expression = input.getExpression(); | ||
int answer = bc.doCalculate(expression); | ||
output.printAnswer(answer); | ||
resultManager.save(expression, answer); |
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.
실행되는 application
과 계산하는 calculator
가 한 클래스에 같이 있는 것 같아요!
public interface Output { | ||
void showMenu(); | ||
void inputError(); | ||
void readAllResults(Map<Integer, String> map); |
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.
Map은 다양한 형태의 값이 들어올 수 있을 것 같아요! 이런 부분에 대한 검증을 할 수 있는 클래스로 변경하거나 검증 로직이 있어야할 것 같아요!
CALCULATE("2"), | ||
EXIT("3"); | ||
|
||
private final String menu; |
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.
Mene
라는 클래스의 menu
라는 필드는 네이밍이 적절해 보이지 않아요! 아래에서 number
와 변수명과 동일성을 비교하기 떄문에 관련해서 유사한 네이밍을 가져가면 좋을 것 같아요!
private int key = 0; | ||
|
||
public void save(String expression, int answer) { | ||
results.put(++key, expression + " = " + String.valueOf(answer)); |
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.
[nit]
++key
로 id값을 넣어줄 때는 멀티 쓰레드 환경이라면 동시에 같은 값이 들어갈 수 있을 것 같아요!
자바 내부적으로 할 수 있는 동시성 제어에 대해서 알아보셔도 좋을 것 같아요!
private final AnswerConverter answerConverter = new AnswerConverter(); | ||
|
||
public int doCalculate(String expression) { | ||
List<String> postfixList = postfixConverter.convertInfixToPostfix(expression); | ||
return answerConverter.convertPostfixToAnswer(postfixList); |
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.
식
에서 답
으로 구하는 과정을 일반적으로 계산
이라고 표현하는 것 같은 데 이걸 변환
이라고 해서 그런 지 AnswerConverter
라는 개념이 잘 와닿지 않는 것 같아요.
public class AnswerConverter { | ||
public int convertPostfixToAnswer(List<String> list) { | ||
Stack<Integer> st = new Stack<>(); | ||
for (String now : list) { | ||
if (!now.equals("+") && !now.equals("-") && !now.equals("*") && !now.equals("/")) { | ||
st.push(Integer.parseInt(now)); | ||
continue; | ||
} | ||
Operator operator = Operator.matchOperator(now); | ||
int x = st.pop(); | ||
int y = st.pop(); | ||
st.push(operator.calculate(x, y)); | ||
} | ||
return st.pop(); | ||
} | ||
} |
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
하게 만들지 않은 이유가 있을까요?
@DisplayName("계산기 테스트") | ||
@Test | ||
void basicCalculatorTest() { | ||
String str = "3 + 2 + 4 * 5 + 3 / 1"; | ||
int result = bc.doCalculate(str); | ||
assertThat(result).isEqualTo(28); | ||
} |
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.
잘못된 문장이 들어오거나 공백 없이 들어오는 경우 등에 다른 케이스에 대해서는 테스트를 안하는 이유가 있을까요?
3 / 2
같은 표현에 대해서 계산 결과가 int
형이라면 정확하지 않을 것 같은 데 어떻게 생각하시나요?
assertThat(Menu.matchMenu(1)).isEqualTo(Menu.LOOK_UP); | ||
assertThat(Menu.matchMenu(2)).isEqualTo(Menu.CALCULATE); | ||
assertThat(Menu.matchMenu(3)).isEqualTo(Menu.EXIT); |
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.
동일한 형태의 코드에서 몇몇 파라미터만 변경되고 있어서 많은 중복이 발생하고 있어요
ParameterizedTest
와 EnumSource
를 찾아보시면 좋을 것 같아요!
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.
안녕하세요 선희님 리뷰남겼습니다.
자바에서는 변수명이나 클래스명을 줄여 사용하지 않습니다. 그리고 의미있는 변수명을 지을 수 있도록 노력하면 좋을 것 같아요.
Menu menu = Menu.matchMenu(input.selectMenu()); | ||
|
||
switch (menu) { | ||
case LOOK_UP -> output.readAllResults(resultManager.readAllResults()); |
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.
메서드가 write로 시작하는 것이 맞지 않을까요?
public Map<Integer, String> readAllResults() { | ||
return results; | ||
} |
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.
복사본을 반환해주는 것이 좋아보이네요. 외부에서 Map 객체를 조작하면 내부가 변경될 수 있을 것 같아요.
새로운 Map 인스턴스를 생성하고 데이터를 복사해서 전달하거나 Collections.unmodifiableMap
을 사용해보는 것도 좋겟네요
public int convertPostfixToAnswer(List<String> list) { | ||
Stack<Integer> st = new Stack<>(); | ||
for (String now : list) { | ||
if (!now.equals("+") && !now.equals("-") && !now.equals("*") && !now.equals("/")) { |
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.
문자열이 연산자인지 판단하는 로직은 Operator에 있어야 할 거 같네요.
mod 연산이 추가 됐다고 상상을 해보면, Operator와 이곳 두 군데를 수정해야하므로 실수가 발생할 수 있을 것 같아요
private final BasicCalculator bc; | ||
|
||
@Override | ||
public void run() { | ||
boolean isExecutable = true; | ||
while (isExecutable) { | ||
while (true) { |
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.
이 부분은 반영전이 더 나은거 같은데 true를 사용하신 이유가 있을까요?
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class ResultManager { |
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.
ResultManager가 model 패키지에 있는게 어색해보이네요. 영속화를 담당하고 있는 것 같아서요
@@ -0,0 +1,16 @@ | |||
package com.programmers.engine.module; |
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.
패키지 이름을 module
이라 지으신 이유가 있을까요?
모듈이라고 하면 여러군데에서 공통적으로 사용하는 것들이 모여있을 것 같아서요
|
||
for (String now: strArr) { | ||
if (now.equals("+") || now.equals("-") || now.equals("*") || now.equals("/")) { | ||
while (!st.isEmpty() && Operator.matchOperator(st.peek()).getPriority() >= Operator.matchOperator(now).getPriority()) { |
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.
우선순위를 판단하는 로직도 Operator가 가져야 할 책임인거 같네요
BasicCalculator bc = new BasicCalculator(); | ||
AnswerConverter ac = new AnswerConverter(); | ||
PostfixConverter pc = new PostfixConverter(); |
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.
접근 제어자도 추가해주세요
@DisplayName("정답 변환기 테스트") | ||
@Test | ||
void answerConverterTest() { | ||
List<String> list = new ArrayList<>(Arrays.asList("3", "2", "+", "4", "5", "*", "+", "3", "1", "/", "+")); | ||
int answer = ac.convertPostfixToAnswer(list); | ||
assertThat(answer).isEqualTo(28); | ||
} | ||
|
||
@DisplayName("후위표기 변환기 테스트") | ||
@Test | ||
void postfixConverterTest() { | ||
String str = "3 + 2 + 4 * 5 + 3 / 1"; | ||
List<String> list = pc.convertInfixToPostfix(str); | ||
List<String> ans = new ArrayList<>(Arrays.asList("3", "2", "+", "4", "5", "*", "+", "3", "1", "/", "+")); | ||
assertThat(list).isEqualTo(ans); | ||
} |
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.
이 테스트는 분리된 클래스에 작성해주면 좋겠네요.
계산 결과를 제대로 반환 하는지 테스트 하는 것이 아니라 후위 표기로 변환이 되는지, 후위 표기식에서 정답이 도출 되는 지 판단하는 테스트라서요
int x = st.pop(); | ||
int y = st.pop(); |
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.
의미있는 변수명을 사용하면 좋겠네요. 순서가 중요하다면 first
, second
정도로 지어줄 수 있을 것 같아요
📌 과제 설명
1~2주차 강의에서 배운 내용들을 최대한 활용할 수 있도록 계산기 구현하였습니다!
더불어 코드리뷰 사항 반영해 보았습니다!
👩💻 요구 사항과 구현 내용
요구 사항
구현 내용
Input
,Output
인터페이스를Console
에서 구현하여 메뉴 입력받기, 수식 입력받기, 메뉴 출력하기, 에러 메시지 출력하기 기능을 구현했습니다.ResultManager
에서 계산 결과 값을 저장할 map을 선언하고 결과값 저장하기, 결과값들 출력하기 기능을 구현했습니다.PostfixConverter
에서 중위표기식을 후위표기식(list)로 바꿔줍니다AnswerConverter
에서 후위표기식을 답으로 변환하여 리턴합니다.BasicCalculator
에서 입력받은 식에 해당하는 답을 반환합니다.JavaCalculator
에서 계산기를 실행할 수 있도록 하였습니다.✅ 피드백 반영사항
ResultManager.java
/engine/BasicCalculator.java
PostfixConverter
,AnswerConverter
convertInfixToPostfix()
ArrayList<String>
->List<String>
✅ PR 포인트 & 궁금한 점
Result.java
에서 결과값을 담을 map을 선언하고 관련 함수들을 같이 선언했는데 이게 좋은 방법인지 궁금합니다!제가 테스트 코드에 익숙하지 않아 계산기 구현 먼저 PR 올렸습니다! 테스트도 더 추가해서 빠르게 올리겠습니다!!!