2019-04-03 [java-study] 문자열 계산기 구현
03 Apr 2019 | java문자열 계산기 구현
기능 요구사항
- 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
- 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다.
- 예를 들어 “2 + 3 * 4 / 2”와 같은 문자열을 입력할 경우 2 + 3 * 4 / 2 실행 결과인 10을 출력해야 한다.
프로그래밍 요구사항
- 메소드가 너무 많은 일을 하지 않도록 분리하기 위해 노력해 본다.
- 규칙 1: 한 메서드에 오직 한 단계의 들여쓰기(indent)만 한다.
- 규칙 2: else 예약어를 쓰지 않는다.
문자열 계산기 구현 중 학습(?)
if - else 문을 사용 하지 않는 이유
- else문 사용시 복잡성 증가 -> else if 문 까지 비교를 해야 if 문이 끝남.
- 한번에 이해하기 힘듬 -> if 문이 쉽다는 느낌이 강함
- 의사소통이 쉬움
TDD란
테스트를 먼저 만들고 테스트를 통과하기 위한 것을 짜는 것.
TDD가 필요한 상황
- 나에 대한 불확실성이 높은 경우
- 외부적 불확실성이 높은 경우
- 개발하는 중에 코들 많이 바꿔야 하는 경우
- 다른사람이 유지 보수를 할 경우
효과
- 피드백 증가
- 남들에게 테스트 코드를 보여주고 그 코드를 직접 실행
- 협력
- 남이 짠 코드 쉽고 빠르게 이해
- 불확실성에 대비
- 버그를 줄일 수 있음.
- 코드 복잡도가 떨어짐 -> 클린 코드 -> 유지보수 비용 감소
단점
- 개발 시간이 늘어남
- 개발 방식을 바꿔야함
Unit 사용법
@Test
public void testSum() {
Calculator calculator = new Calculator();
assertEquals(30, calculator.sum(10, 20));
}
Test 클래스에서 @Test
와 메소드를 생성 -> assertEqulas();
메소드를 이용하여 구현할 코드를 테스트
@Before
public void setUp() {
calculator = new StringCalculator();
}
test 코드를 사용하기 전에 미리 구현할 수 있는 메소드 @before
, public void setUp()
사용
소스코드
StringCalculator.java
import java.util.Scanner;
public class StringCalculator {
public String input() {
Scanner scanner = new Scanner(System.in);
return scanner.nextLine();
}
public boolean isBlank(String input) {
if (input.equals(" ") || input == null)
return true;
return false;
}
public int makeResult(String input) {
if (isBlank(input))
throw new RuntimeException();
return calculateSplitedString(splitBlank(input));
}
public String[] splitBlank(String str) {
return str.split(" ");
}
public int toInt(String str) {
return Integer.parseInt(str);
}
public int calculateSplitedString(String[] str) {
int result = toInt(str[0]);
for (int i = 0; i < str.length - 2; i += 2) {
result = calculate(result, str[i + 1].charAt(0), toInt(str[i + 2]));
}
return result;
}
public int calculate(int firstValue, char operator, int secondValue) {
if (operator == '+')
return add(firstValue, secondValue);
if (operator == '-')
return subtract(firstValue, secondValue);
if (operator == '*')
return multiply(firstValue, secondValue);
if (operator == '/')
return divide(firstValue, secondValue);
throw new RuntimeException();
}
public int add(int i, int j) {
return i + j;
}
public int subtract(int i, int j) {
return i - j;
}
public int multiply(int i, int j) {
return i * j;
}
public int divide(int i, int j) {
try {
return i / j;
} catch (ArithmeticException e) {
System.out.println("숫자 0으로 나눌 수 없습니다.");
}
return i / j;
}
}
StringCalculatorTest
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class StringCalculatorTest {
StringCalculator calculator;
@Before
public void SetUp() {
calculator = new StringCalculator();
}
@Test
public void testAdd() {
assertEquals(3, calculator.add(1, 2));
}
@Test
public void testSubtract() {
assertEquals(1, calculator.subtract(3, 2));
}
@Test
public void testMultiply() {
assertEquals(8, calculator.multiply(4, 2));
}
@Test
public void testDivide() {
assertEquals(2, calculator.divide(8, 4));
}
@Test
public void testCalculate() {
assertEquals(6, calculator.makeResult("1 + 2 * 4 / 2"));
}
@Test(expected = ArithmeticException.class)
public void testDivideZero() {
calculator.divide(3, 0);
}
@Test
public void test계산() {
assertEquals(5, calculator.calculate(1, '+', 4));
}
@Test(expected = RuntimeException.class)
public void testIsBlankError() {
calculator.makeResult(" ");
}
}
Comments