Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3d4ec74
docs(guide): list of implementation functions and TDD case
oereo Feb 23, 2021
59160fa
docs(guide): add TDD case
oereo Feb 24, 2021
fd2266a
feat: java-calculator basic structure design and implementation
oereo Feb 25, 2021
25e3e7a
feat: add a method to initialize and rerun the calculator
oereo Feb 25, 2021
3f697e6
feat: add exception message list
oereo Feb 25, 2021
a0723cc
refactor: fix message format in ErrorException and Message class
oereo Feb 25, 2021
9aab010
refactor: delete unused parameter in OperatorSetting class
oereo Feb 25, 2021
f53fdf9
Merge pull request #1 from oereo/feature/java-calculator
oereo Feb 25, 2021
ef52572
refactor: delete the userInputData class
oereo Feb 25, 2021
9199b85
refactor: reset variable names that don't fit naming
oereo Feb 25, 2021
860bcd7
refactor: rename variable name [exception]
oereo Feb 25, 2021
b6d6340
Merge pull request #2 from oereo/fix/java-calculator
oereo Feb 25, 2021
529f7e4
feat: add TDD basic format and test case for calculator class
oereo Feb 25, 2021
52021fa
Merge pull request #3 from oereo/fix/java-calculator-TDD
oereo Feb 25, 2021
02edb1f
refactor: fix exception handling part divided by 0
oereo Feb 25, 2021
c3b416c
feat: add comments to those classes and methods
oereo Feb 25, 2021
fc69dd8
Merge pull request #4 from oereo/feature/java-calculator-comment
oereo Feb 26, 2021
825f9c8
feat: add invalid test case
oereo Feb 26, 2021
8081d30
Merge pull request #5 from oereo/feature/java-calculator-TDD-invalid
oereo Feb 26, 2021
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
2 changes: 2 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rootProject.name = 'java-calculator'

61 changes: 61 additions & 0 deletions src/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Java-Calculator

Create a string calculator and write test code for it

## Contributor
- oereo

## Branch structure

### oereo branch
* from `oereo/java-calculator[oereo branch]` to `biforest/java-calculator [oereo branch]`

### java-calculator-structure branch
* Feature branch : Branch to develop the function ex)feature/java-calculator
* Fix branch : Branch to fix the function ex)fix/java-calculator

## TDD
### Failure case
#### (1) When divided by 0
```console
연산을 입력해주세요 : 2/0 // error
```
#### (2) When two or more operation symbols appear in a row
```console
연산을 입력해주세요 : 2++0 // error
```
#### (3) When the operation symbol appears at the beginning
```console
연산을 입력해주세요 : +2+0 // error
```
#### (4) When special characters other than operation symbols are entered
```console
연산을 입력해주세요 : 2^4 // error
```
#### (5) When characters excluding numbers and operators are entered
```console
연산을 입력해주세요 : 2ㄱㄴ4*4 // error
```
#### (6) When the formula ends with an operation symbol
```console
연산을 입력해주세요 : 2-1* // error
```
## Structure
#### 1. Class
- Calculator class
- `+ class`
- `- class`
- `* class`
- `/ class`
- Input class
- Output class
- `Error message` output
- `Calculation result` output
- Error exception class
- Precautions : only use `try ~ catch`
- Init class
- When an error occurs, reset after outputting an error message
- Reset and input when pressing any key value

#### 2. Algorithm
- DFS, Node
19 changes: 19 additions & 0 deletions src/main/java/calculator/AddOperation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package calculator;

public class AddOperation implements OperationInterface {
@Override
public int operationPriority() {
return 1;
}

@Override
public String operationName() {
return "+";
}

@Override
public int calculation(int beforeNumber, int afterNumber) {
int Result = beforeNumber + afterNumber;
return Result;
}
}
11 changes: 11 additions & 0 deletions src/main/java/calculator/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package calculator;


public class Application {
public static void main(String[] args) {

// Declare calculator object and start calculation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석은 코드로 표현할 수 없는 상황에만 적어주세요.
최대한 주석을 사용하지 않고 코드를 이해할 수 있게 만드는게 좋습니다 🙂

Calculator calculator = new Calculator();
calculator.calculation();
}
}
46 changes: 46 additions & 0 deletions src/main/java/calculator/ArithmeticExpressionStack.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package calculator;


interface Stack{
boolean isEmpty();
String pop();
void clear();
}
Comment on lines +4 to +8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

java.util.Stack이 이미 존재한답니다. 따로 구현해줄 이유가 있었을까요?
java.util의 Stack을 활용하여 ArithmeticExpressionStack 클래스를 리팩토링 해보도록해요 🙂

바퀴의 재발명

이미 있는 라이브러리나 프레임워크를 다시 만들지 말라.


public class ArithmeticExpressionStack implements Stack {
private int stackSize;
private int flag;
private String stack[];

public ArithmeticExpressionStack(String[] equation, int stackSize){
clear();
flag = 0;
this.stackSize = stackSize;
stack = equation;
}

public String pop(){
if(isEmpty()){
return "스택이 존재하지 않습니다.";
}
else{
return stack[flag++];
}
}

public boolean isEmpty(){
return (flag == this.stackSize);
}

public void clear(){
if(!isEmpty()){
flag = -1;
this.stackSize = stackSize;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

대입하는 stackSize는 어디서 나온 변수인가요??🤔

}
}

public int getStackSize(){
return this.stackSize;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return this.stackSize;
return stackSize;
public ArithmeticExpressionStack(String[] equation, int stackSize){
        this.stackSize = stackSize;
    }

이 경우와 같이 클래스의 속성과 메소드의 매개변수의 이름이 같은경우가 아니므로 굳이 this. 을 써주지 않아도 될 것 같아요~

}

}
132 changes: 132 additions & 0 deletions src/main/java/calculator/Calculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package calculator;

import java.util.Scanner;


public class Calculator {
Message message = new Message();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

멤버 변수의 접근 제어자가 default인데 의도한 부분인가요?


/**
* calculation method
* 1. getEquation - Receives numeric expression in string format entered by user
* 2. Put numeric expressions on the stack
* 3. Passing the stack to the operatorSetting method
*
* return type : void
*/
Comment on lines +9 to +16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javadoc을 만들땐 @를 활용하여 tag를 사용할 수 있습니다. (@param, @exception 등)
하지만 라이브러리를 만드는것이 아닌 어플리케이션을 만드는 과정이니, 주석이나 javadoc이 필수는 아닙니다.

최대한 코드만 읽어도 이해할 수 있도록 만드는걸 목표로 해보세요.
(클린코드의 저자 martin은 명쾌한 추상화라는 표현을 굉장히 좋아했었습니다.)

public void calculation(){
String[] equation_list = getEquation();
Comment on lines +17 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calculation(), equation_list보다는 calculate()equaitonList가 좋은 이름 같아요~

ArithmeticExpressionStack arithmeticExpressionStack = new ArithmeticExpressionStack(equation_list, equation_list.length);
OperatorSetting(arithmeticExpressionStack);

}

/**
* OperatorSetting method
* 1. Pop each operator and number onto the stack.
* 2. Perform error exception check and calculate
* 3. After the calculation process is complete, call init() to determine whether to return the calculator
*
* return type : void
*/
public void OperatorSetting(ArithmeticExpressionStack arithmeticExpressionStack) {
ErrorException exceptionCheck = new ErrorException();
String firstString = arithmeticExpressionStack.pop();

// Error checking when converting string to int
int cumulativeResult = exceptionCheck.NumericalError(firstString);

for(int i = 0; i<(arithmeticExpressionStack.getStackSize())/2;i++){
String operator = arithmeticExpressionStack.pop();
String secondString = arithmeticExpressionStack.pop();
int secondNumber = exceptionCheck.NumericalError(secondString);

// calculated value are continuously accumulated
cumulativeResult = chooseOperatorAndCalculate(cumulativeResult, operator, secondNumber);
}

if(cumulativeResult != 0){
message.calculationResult(cumulativeResult);
}
Comment on lines +48 to +50
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 - 2같이 결과값이 0이 나오는 경우도 고려해주어야 할 것 같아요


// Whether to re-execute after calculation
init();
}

/**
* chooseOperatorAndCalculate method
* 1. Pop each operator and number onto the stack.
* 2. Perform error exception check and calculate
* 3. After the calculation process is complete, call init() to determine whether to return the calculator
*
* return type : int
*/
public int chooseOperatorAndCalculate(int firstNumber, String operator, int SecondNumber){
AddOperation addOperation = new AddOperation();
SubOperation subOperation = new SubOperation();
MultiplyOperation multiplyOperation = new MultiplyOperation();
DivideOperation divideOperation = new DivideOperation();
Comment on lines +65 to +68
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for문을 돌 때마다 각 Operation을 생성해야하니까 Caculator의 필드로 먼저 선언해놓는 방식은 어떨까요?

Comment on lines +65 to +68
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모든 Operation을 미리 생성해 놔야할까요?

int result = 0;

// When the operator is equal to "+"
if (operator.equals(addOperation.operationName())){
result = addOperation.calculation(firstNumber, SecondNumber);
}

// When the operator is equal to "-"
else if (operator.equals(subOperation.operationName())){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if ~ else 체인을 최대한 사용하지 말아보세요. 다형성이나 enum을 활용하면 해결할 수 있습니다.

result = subOperation.calculation(firstNumber, SecondNumber);
}

// When the operator is equal to "*"
else if (operator.equals(multiplyOperation.operationName())){
result = multiplyOperation.calculation(firstNumber, SecondNumber);
}

// When the operator is equal to "/"
else if (operator.equals(divideOperation.operationName())){
result = divideOperation.calculation(firstNumber, SecondNumber);
}

// Raise error when a symbol that does not correspond to the arithmetic operations(+, -, *, /) comes
else{
message.exceptionResult("NOT_OPERATOR");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Message.exceptionResult()는 예외를 던지지 않고 메세지만 출력해주는 메서드인것 같아요
이 경우에는 for문이 계속 돌지 않을까요?

}

return result;
}

/**
* init method
* - Input "1" to redo calculator.
* - Input another key to exit
*
* return type : void
*/
public void init(){
Scanner scanner = new Scanner(System.in);
System.out.println("계산을 계속 진행하시려면 1, 멈추시려면 임의의 다른키를 눌러주세요");
String value = scanner.nextLine();

if(value.equals("1")){
calculation();
}
else{
System.exit(0);
}
}

/**
* getEquation method
* - Method to receive user input data
*
* return type : void
*/
public String[] getEquation(){
Scanner scanner = new Scanner(System.in);
System.out.print("수식을 입력해주세요 : ");
String value = scanner.nextLine();
String[] values = value.split(" ");
return values;
}
}
26 changes: 26 additions & 0 deletions src/main/java/calculator/DivideOperation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package calculator;

public class DivideOperation implements OperationInterface {
@Override
public int operationPriority() {
return 1;
}

@Override
public String operationName() {
return "/";
}

@Override
public int calculation(int beforeNumber, int afterNumber) {
Message message = new Message();
try{
int Result = beforeNumber / afterNumber;
return Result;
}
catch (ArithmeticException e){
message.exceptionResult("INVALID_DIVIDE");
}
return 0;
}
}
25 changes: 25 additions & 0 deletions src/main/java/calculator/ErrorException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package calculator;

import java.util.InputMismatchException;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용되지 않는 부분이니 지워주세요 🙂


public class ErrorException {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 클래스는 NumberFormatException 에 관한 메서드밖에 없으니 클래스명을 그에 맞게 바꾸는건 어떨까요?

Message message = new Message();

/**
* NumericalError method
* - Raise error when string is not converted to int
*
* return type : void
*/
public int NumericalError(String number) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드명은 소문자 카멜표기법을 사용하고, 동사나 전치사로 시작하기 때문에 checkNumericalException 이런 식으로 메서드에 맞게 바꾸는게 나을 것 같아요!

int numberConverted = 0;
try {
numberConverted = Integer.parseInt(number);
} catch (NumberFormatException e) {
message.exceptionResult("INVALID_EQUATION");
Calculator calculator = new Calculator();
calculator.init();
}
return numberConverted;
}
}
32 changes: 32 additions & 0 deletions src/main/java/calculator/Message.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package calculator;

import java.util.HashMap;

/**
* Message class
* - message output class
*
* return type : void
*/
public class Message {
HashMap<String, String> exceptionMessageList = new HashMap<String, String>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

객체지향의 유명한 규칙중 Program to Interface 라는 규칙이 있습니다.

Suggested change
HashMap<String, String> exceptionMessageList = new HashMap<String, String>();
Map<String, String> exceptionMessageList = new HashMap<>();

구체클래스가 아닌 인터페이스로 사용하는것은 어떤 장점이 있을까요?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

에러처리는 Exception을 활용하여 처리할 수 있습니다.
System.exit 대신 자바의 Exception을 활용해보세요 🙂


// Result output method when operation is normally performed
public void calculationResult(int result){
System.out.print("결과 : ");
System.out.println(result);
}
Comment on lines +14 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드명을 계산 결과를 출력한다라는 의미를 담게 수정하면 좋을 것 같아요

그리고 이 메서드를 계산결과를 출력할 때 한 번만 사용되므로 caculationResult()가 사용되는 클래스로 위치로 옮기고
Message 클래스를 예외 메세지 처리할 때만 사용하는 방식은 어떨까요?


// Error message list management method
private void exceptionMessageList(){
exceptionMessageList.put("NOT_OPERATOR", "사칙연산 기호에 해당하지 않는 기호가 존재합니다.");
exceptionMessageList.put("INVALID_EQUATION", "잘못된 연산식입니다.");
exceptionMessageList.put("INVALID_DIVIDE", "0으로 나눌수가 없습니다.");
}

// Error message output method
public void exceptionResult(String exceptionKeyword){
exceptionMessageList();
System.out.println(exceptionMessageList.get(exceptionKeyword));
}
Comment on lines +28 to +31
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public void exceptionResult(String exceptionKeyword){
exceptionMessageList();
System.out.println(exceptionMessageList.get(exceptionKeyword));
}
public void exceptionResult(String exceptionKeyword){
System.out.println(exceptionMessageList.get(exceptionKeyword));
}

제가 위에서 말한 방식대로라면 exceptionMessageList()를 생성자에서 호출하고
exceptionResult()getExceptionResult() 등의 이름으로 변경해서 해당 exceptionKeyword에 맞는 예외 메세지를 가져오는 메서드로만 사용할 수 있겠네요!

}
19 changes: 19 additions & 0 deletions src/main/java/calculator/MultiplyOperation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package calculator;

public class MultiplyOperation implements OperationInterface {
@Override
public int operationPriority() {
return 1;
}

@Override
public String operationName() {
return "*";
}

@Override
public int calculation(int beforeNumber, int afterNumber) {
int Result = beforeNumber * afterNumber;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

클래스의 시작은 대문자, 변수의 시작은 소문자입니다 🙂

Suggested change
int Result = beforeNumber * afterNumber;
int result = beforeNumber * afterNumber;

return Result;
}
}
14 changes: 14 additions & 0 deletions src/main/java/calculator/Operation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package calculator;

interface OperationInterface {
public int operationPriority();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 함수는 사용되지 않고 OperationInterface를 어떤 용도로 구현하려한건지 궁급합니다!
그리고 이 인터페이스를 상속받는 모든 클래스에서 다 return 1;로 같은 값을 반환하던데 추상 클래스로 구현해도 될 것 같다는 생각이 드네요

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 요구사항에서 operationPriority가 필요할까요?


public String operationName();

public int calculation(int beforeNumber, int afterNumber);
}





Comment on lines +11 to +14
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

필요없는 공백이 들어간 것 같네요

Loading