Java Enum (계산기 구현)
계산기 구현
우아한테크코스 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번째 코드가 개인적으로는 더 마음에 든다.
더 좋은 코드가 분명 있겠지만. 현재까지의 지식으로는 여기까지.
더 좋은 코드가 생각나면 업데이트 해야겠다.
댓글남기기