Java Enum (계산기 구현)

2 분 소요

계산기 구현

우아한테크코스 1단계 미션 중 1주차에 했던 자동차 경주 게임에서 기본 미션으로 계산기를 구현하는 미션이 있었다.

그걸 이제 와서 생각해보니 이런 방식으로 구현을 해도 되지 않을까? 하면서 다시 코드를 작성해봤다.

원래 코드

package calculator;

public class Calculator {
    double add(double a, double b) {
        return a + b;
    }

    double subtract(double a, double b) {
        return a - b;
    }

    double multiply(double a, double b) {
        return a * b;
    }

    double divide(double a, double b) {
        return a / b;
    }

    double calculate(double a, String operator, double b) {
        if (operator.equals("+")) {
            return add(a, b);
        }
        if (operator.equals("-")) {
            return subtract(a, b);
        }
        if (operator.equals("*")) {
            return multiply(a, b);
        }
        if (operator.equals("/")) {
            return divide(a, b);
        }

        throw new IllegalArgumentException("올바른 연산자가 아닙니다.");
    }
}

원래 코드는 이런 상태였다.

else if를 안썼을 뿐이지.. if 문이 4개 연속으로 나오고.. 각각 분기해서 method를 호출해서 결과를 뿌려주는 건 똑같았다.

그래서 enum을 활용했다. enum을 활용하면서 BiFunction과 Optional의 null 처리들을 배워서 알고 있었기 때문에 최대한 활용해봤다.

그래서 나온 코드는 아래와 같다.

1번째 코드

import java.util.Arrays;
import java.util.function.BiFunction;

public enum Operator {
    PLUS("+", (num1, num2) -> num1 + num2),
    MINUS("-", (num1, num2) -> num1 - num2),
    MULTIPLY("*", (num1, num2) -> num1 * num2),
    DIVIDE("/", (num1, num2) -> num1 / num2);

    private String operator;
    private BiFunction<Double, Double, Double> expression;

    Operator(String operator, BiFunction<Double, Double, Double> expression) {
        this.operator = operator;
        this.expression = expression;
    }

    public static double calculate(String operator, double num1, double num2) {
        return getOperator(operator).expression.apply(num1, num2);
    }

    private static Operator getOperator(String operator) {
        return Arrays.stream(values())
                .filter(o -> o.operator.equals(operator))
                .findFirst().orElseThrow(() -> new IllegalArgumentException("올바른 연산자가 아닙니다."));
    }
}

package calculator;

public class Calculator {
    double calculate(double a, String operator, double b) {
        return Operator.calculate(operator, a, b);
    }
}

Calculator Class 내부에 calculate 메서드 내 if문 없이 작성 했다.

getOperator 메서드에 stream.filter를 썼으니까 이게 조건문이 아예 없는 건 아닌 것 같은데..

그러면 operator를 key로 하고 value를 Operator enum을 갖는 map을 만들어서

그 맵에서 꺼내오는 것으로 하면 완전히 조건문을 없애고 사용할 수 있을 것 같다.

그렇게 코드를 작성해보면 아래와 같이 작성 될 것 같다.

2번째 코드

public class Calculator {
    private static Map<String, Operator> operatorMap = new HashMap<>();

    static {
        operatorMap.put("+", Operator.PLUS);
        operatorMap.put("-", Operator.MINUS);
        operatorMap.put("*", Operator.MULTIPLY);
        operatorMap.put("/", Operator.DIVIDE);
    }

    double calculate(double a, String operator, double b) {
        return Optional.ofNullable(operatorMap.get(operator))
                .orElseThrow(() -> new IllegalArgumentException("잘못된 연산자 입력입니다."))
                .mapCalculate(a, b);
    }
}
package calculator;

import java.util.Arrays;
import java.util.function.BiFunction;

public enum Operator {
    PLUS("+", (num1, num2) -> num1 + num2),
    MINUS("-", (num1, num2) -> num1 - num2),
    MULTIPLY("*", (num1, num2) -> num1 * num2),
    DIVIDE("/", (num1, num2) -> num1 / num2);

    private String operator;
    private BiFunction<Double, Double, Double> expression;

    Operator(String operator, BiFunction<Double, Double, Double> expression) {
        this.operator = operator;
        this.expression = expression;
    }

    public double mapCalculate(double num1, double num2) {
        return expression.apply(num1, num2);
    }
}

그런데 만약에 연산자가 하나 추가 된다고 했을 때 두번째 코드들은 Operator enum과 Calculator class 내부에 각각 추가 해줘야 한다.

그러면 추가되는 연산자가 늘어날 수록 개발자의 실수가 들어갈 수 있을 것 같다.

연산자가 추가 되면 Operator enum안에 연산자만 추가하고,

그 내부에서 예외 처리까지 다 해주면 그 메서드를 사용하는 쪽에서는 전혀 신경쓰지 않고 사용만 하면 되기 때문에 1번째 코드가 개인적으로는 더 마음에 든다.

더 좋은 코드가 분명 있겠지만. 현재까지의 지식으로는 여기까지.

더 좋은 코드가 생각나면 업데이트 해야겠다.

태그:

카테고리:

업데이트:

댓글남기기