Develope Story

2019-04-03 [java-study] 문자열 계산기 구현

|

문자열 계산기 구현

기능 요구사항

  • 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
  • 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다.
  • 예를 들어 “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