Skip to content
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

[또링] 온보딩 코드리뷰 요청합니다. #37

Merged
merged 28 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2bb20b3
[Add] split method
kimevanjunseok Feb 5, 2020
e175d57
[Add] substring method
kimevanjunseok Feb 5, 2020
4923054
[Add] charAt method with using assertThatThrownBy
kimevanjunseok Feb 5, 2020
3b70d9f
[Refactor] add class information
kimevanjunseok Feb 5, 2020
d7d14a9
[Docs] add README
kimevanjunseok Feb 5, 2020
f614840
[Refactor] split test using containsExactly()
kimevanjunseok Feb 5, 2020
ba9a772
[Docs] update README
kimevanjunseok Feb 5, 2020
00b743c
[Add] method to check size of Set
kimevanjunseok Feb 5, 2020
4e97baa
[Add] method to check if Set contains value using @ParameterizedTest
kimevanjunseok Feb 5, 2020
370f685
[Add] method to check if Set contains value in all cases
kimevanjunseok Feb 5, 2020
26c78d6
[Refactor] separate charAt method
kimevanjunseok Feb 5, 2020
1a88b09
[Docs] update README
kimevanjunseok Feb 5, 2020
2f72d1c
[Docs] update README about calculator
kimevanjunseok Feb 6, 2020
64f7e39
[Add] function to get string from user
kimevanjunseok Feb 6, 2020
090387b
[Add] validation of input value
kimevanjunseok Feb 6, 2020
3b65b88
[Add] Test code about validation of input value
kimevanjunseok Feb 6, 2020
9bcabf0
[Update] function to get string from user
kimevanjunseok Feb 6, 2020
ef2e8a0
[Add] function to calculate value
kimevanjunseok Feb 6, 2020
787dec9
[Add] Test code about function to calculate value
kimevanjunseok Feb 6, 2020
ffb2fb2
[Add] function to print result
kimevanjunseok Feb 6, 2020
6635bd2
[Refactor] code separation
kimevanjunseok Feb 7, 2020
1a87428
[Refactor] handle exception about divide
kimevanjunseok Feb 7, 2020
7dc5b38
[Add] Test code about divide exception function
kimevanjunseok Feb 7, 2020
3e96b56
[Refactor] renaming of variables and method
jnsorn Feb 9, 2020
e790882
[Refactor] static variables, handle NPE
jnsorn Feb 9, 2020
07e22f0
[Refactor] create Expression object after validation
jnsorn Feb 9, 2020
1542a3a
[Refactor] managing four operators as enum
jnsorn Feb 9, 2020
6d63357
[Refactor] simple calculation logic using enum
jnsorn Feb 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,64 @@
문자열 계산기 미션 저장소

## 우아한테크코스 코드리뷰
* [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
* [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)

## 1단계 - 학습 테스트

### String 클래스에 대한 학습 테스트

##### 요구사항 1

- "1,2"을 `,`로 split 했을 때 1과 2로 잘 분리되는지 확인하는 학습 테스트를 구현한다.
- "1"을 `,`로 split 했을 때 1만을 포함하는 배열이 반환되는지에 대한 학습 테스트를 구현한다.

##### 요구사항 2

- "(1,2)" 값이 주어졌을 때 String의 substring() 메소드를 활용해 `()`을 제거하고 "1,2"를 반환하도록 구현한다.

##### 요구사항 3

- "abc" 값이 주어졌을 때 String의 charAt() 메소드를 활용해 특정 위치의 문자를 가져오는 학습 테스트를 구현한다.
- String의 charAt() 메소드를 활용해 특정 위치의 문자를 가져올 때 위치 값을 벗어나면 StringIndexOutOfBoundsException이 발생하는 부분에 대한 학습 테스트를 구현한다.
- JUnit의 @DisplayName을 활용해 테스트 메소드의 의도를 드러낸다.

### Set Collection에 대한 학습 테스트

##### 요구사항 1

- Set의 size() 메소드를 활용해 Set의 크기를 확인하는 학습테스트를 구현한다.

##### 요구사항 2

- Set의 contains() 메소드를 활용해 1, 2, 3의 값이 존재하는지를 확인하는 학습테스트를 구현하려한다.
- 구현하고 보니 다음과 같이 중복 코드가 계속해서 발생한다.
- JUnit의 ParameterizedTest를 활용해 중복 코드를 제거해 본다.

##### 요구사항 3

- 요구사항 2는 contains 메소드 결과 값이 true인 경우만 테스트 가능하다. 입력 값에 따라 결과 값이 다른 경우에 대한 테스트도 가능하도록 구현한다.

### 2단계 - 단위 테스트

- 다음 요구사항을 junit을 활용해 단위 테스트 코드를 추가해 구현한다.

##### 요구사항

- 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
- 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다.
- 예를 들어 "2 + 3 * 4 / 2"와 같은 문자열을 입력할 경우 2 + 3 * 4 / 2 실행 결과인 10을 출력해야 한다.

##### 기능구현

1. 사용자 문자열 입력
2. 입력값에 대한 계산기 기능 구현
1. 예외처리 기능
1. 시작과 끝은 숫자인지 판단
2. 하나 이상의 부호가 있는지 판단
3. 숫자와 사칙연산 부호만으로 이루어져있는지 판단
2. 계산 기능 구현
1. 입력 순서에 따라 계산기능
1. 부호가 나오기 전까지 숫자를 문자열로 저장(StringBuilder/List<String>)
2. 첫번째 숫자이면 바로 sum변수에 저장(그 이후 숫자는 num변수에 저장하여 해당 함수에 sum과 num를 전달한다.)
3. 결과값 출력
1. sum최종 결과 값 출력
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ repositories {
dependencies {
testCompile('org.junit.jupiter:junit-jupiter:5.4.2')
testCompile('org.assertj:assertj-core:3.11.1')
testCompile("org.junit.jupiter:junit-jupiter-params:5.4.2")
}
33 changes: 33 additions & 0 deletions src/main/java/calculator/Calculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2019 by 또링
* All rights reserved.
*
* Calculator.java
* 계산을 담당하는 클래스
*
* @author 또링
* @version 1.0
* @date 09 Feb 2020
*
*/

package calculator;

import model.OperatorType;

public class Calculator {
private OperatorType operatorType;

public void setOperatorType(String operator) {
for (OperatorType op : OperatorType.values()) {
if (operator.equals(op.toString())) {
operatorType = op;
}
}
jnsorn marked this conversation as resolved.
Show resolved Hide resolved
}

public double calculate(double number1, double number2) {
return operatorType.calculate(number1, number2);
}
}

55 changes: 55 additions & 0 deletions src/main/java/controller/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2019 by 또링
* All rights reserved.
*
* Controller.java
* Expression 객체를 이용하여 계산을 하고 View를 통해 입출력을 제어하는 클래스
*
* @author 또링
* @version 1.0
* @date 09 Feb 2020
*
*/

package controller;

import calculator.Calculator;
import model.Expression;
import validator.InputValidator;
import view.InputView;
import view.OutputView;

import java.util.List;

public class Controller {

public void run() {
String input;
InputValidator inputValidator = new InputValidator();

do {
input = InputView.inputStringFromUser();
} while (!inputValidator.validateExpression(input));

Expression expression = new Expression(input);

double sum = calculate(expression);

OutputView.print(sum);
}

private double calculate(Expression expression) {
List<Double> numbers = expression.getNumbers();
List<String> operators = expression.getOperators();

double result = numbers.get(0);
Calculator calculator = new Calculator();

for (int i = 0; i < operators.size(); i++) {
calculator.setOperatorType(operators.get(i));
result = calculator.calculate(result, numbers.get(i + 1));
}

return result;
}
}
Empty file removed src/main/java/empty.txt
Empty file.
22 changes: 22 additions & 0 deletions src/main/java/main/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2019 by 또링
* All rights reserved.
*
* Main.java
* 프로그램 시작을 담당하는 클래스
*
* @author 또링
* @version 1.0
* @date 09 Feb 2020
*
*/

package main;

import controller.Controller;

public class Main {
public static void main(String[] args) {
new Controller().run();
}
}
49 changes: 49 additions & 0 deletions src/main/java/model/Expression.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2019 by 또링
* All rights reserved.
*
* Expression.java
* 입력 값 객체
*
* @author 또링
* @version 1.0
* @date 09 Feb 2020
*
*/
package model;

import validator.InputValidator;

import java.util.ArrayList;
import java.util.List;

public class Expression {
private String expression;
private List<Double> numbers = new ArrayList<>();
private List<String> operators = new ArrayList<>();

public Expression(String expression) {
this.expression = expression;
setValueList();
}

public void setValueList() {
String[] componentOfExpression = expression.split(InputValidator.BLANK);
for (int i = 0; i < componentOfExpression.length; i++) {
if (i % 2 == 0) {
numbers.add(Double.parseDouble(componentOfExpression[i]));
}
if (i % 2 == 1) {
operators.add(componentOfExpression[i]);
}
}
}

public List<Double> getNumbers() {
return numbers;
}

public List<String> getOperators() {
return operators;
}
}
55 changes: 55 additions & 0 deletions src/main/java/model/OperatorType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package model;

/*
* Copyright (c) 2019 by 또링
* All rights reserved.
*
* OperatorType.java
* 연산자를 관리하는 enum
*
* @author 또링
* @version 1.0
* @date 09 Feb 2020
*
*/

public enum OperatorType {
jnsorn marked this conversation as resolved.
Show resolved Hide resolved
PLUS("+") {
@Override
public double calculate(double number1, double number2) {
return number1 + number2;
}
},
MINUS("-") {
@Override
public double calculate(double number1, double number2) {
return number1 - number2;
}
},
MUL("*") {
@Override
public double calculate(double number1, double number2) {
return number1 * number2;
}
},
DIV("/") {
@Override
public double calculate(double number1, double number2) {
return number1 / number2;
}
};

final private String operator;
jnsorn marked this conversation as resolved.
Show resolved Hide resolved

OperatorType(String operator) {
this.operator = operator;
}

@Override
public String toString() {
return operator;
}

public abstract double calculate(double number1, double number2);

}
88 changes: 88 additions & 0 deletions src/main/java/validator/InputValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2019 by 또링
* All rights reserved.
*
* InputValidator.java
* 값 유효성 검사를 담당하는 클래스
*
* @author 또링
* @version 1.0
* @date 09 Feb 2020
*
*/

package validator;

import model.OperatorType;

import java.util.ArrayList;
import java.util.List;

public class InputValidator {
public static final String BLANK = " ";
private static final String ZERO = "0";
private static final int EVEN = 0;
private static final int ODD = 1;

public boolean validateExpression(String expression) {
String[] expressionArr = expression.split(BLANK);
return isCorrectLength(expressionArr) && isCorrectIndex(expressionArr) && isNotDivideByZero(expressionArr);
}

public boolean isCorrectLength(String[] expressionArr) {
return expressionArr.length % 2 == ODD;
}

private boolean isCorrectIndex(String[] expressionArr) {
List<String> evenIndexOfExpression = getEvenOrOddArr(EVEN, expressionArr);
List<String> oddIndexOfExpression = getEvenOrOddArr(ODD, expressionArr);

return isNumberAllElements(evenIndexOfExpression) && isRightOperatorAllElements(oddIndexOfExpression);
}

private List<String> getEvenOrOddArr(int num, String[] inputArr) {
List<String> evenOrOddList = new ArrayList<>();
for (int i = 0; i < inputArr.length; i++) {
if (i % 2 == num) {
evenOrOddList.add(inputArr[i]);
}
}
return evenOrOddList;
}

public boolean isNumberAllElements(List<String> evenIndexOfExpression) {
for (String number : evenIndexOfExpression) {
try {
Integer.parseInt(number);
} catch (NumberFormatException e) {
return false;
}
}
return true;
}

public boolean isRightOperatorAllElements(List<String> oddIndexOfExpression) {
List<String> fourOperators = new ArrayList<>();

for (OperatorType op : OperatorType.values()) {
fourOperators.add(op.toString());
}

for (String operator : oddIndexOfExpression) {
if (!fourOperators.contains(operator)) {
return false;
}
}

return true;
}

public boolean isNotDivideByZero(String[] expression) {
for (int i = 2; i < expression.length; i += 2) {
if (ZERO.equals(expression[i]) && expression[i - 1].equals(OperatorType.DIV.toString())) {
return false;
}
}
return true;
}
}
Loading