기존 OperatorType
- 연산자 클래스별로 연산자를 나타내는 char값만 존재함
public enum OperatorType {
ADD('+'),
SUBTRACT('-'),
MULTIPLY('*'),
DIVIDE('/');
private final char operator;
public char getOperator(){
return operator;
}
OperatorType(char operator) {
this.operator = operator;
}
}
public class ArithmeticCalculator {
private OperatorType addOperator = OperatorType.ADD;
private OperatorType subtractOperator = OperatorType.SUBTRACT;
private OperatorType divideOperator = OperatorType.DIVIDE;
private OperatorType multiplyOperator = OperatorType.MULTIPLY;
private ArrayList<Double> results = new ArrayList<>();
public <T extends Number> Double calculate(T number1, T number2, char operator){
double answer = 0.0;
//연산 수행
if (operator == addOperator.getOperator()) {
answer = number1.doubleValue() + number2.doubleValue();
} else if (operator == subtractOperator.getOperator()) {
answer = number1.doubleValue() - number2.doubleValue();
} else if (operator == multiplyOperator.getOperator()) {
answer = number1.doubleValue() * number2.doubleValue();
} else if (operator == divideOperator.getOperator()) {
answer = number1.doubleValue() / number2.doubleValue();
}
results.add(answer);
return answer;
}
}
이런식으로 Enum 클래스에 연산자만 선언해서 계산기 클래스 내부에서 해당 연산자값을 비교해오는 방식으로 사용했었는데, 아무리 생각해봐도 뭔가 연산자만 비교하기에는 아쉬운 것 같다는 생각이 들었다. 연산자 char 값만 비교하기에는 너무 메모리상으로도 낭비같고 차라리 계산기 클래스 내부에서 static final로 상수를 선언하면 되지 않나 싶었다.
그래서 연산자 값 뿐만 아니라 차라리 메서드를 Enum 클래스에서 따로 구현해서 수행하는 편이 훨씬 의미가 있을 거라는 생각이 들었다. 나중에 더하기 로직을 내부적으로 +10 씩 더한다거나 등등 유지보수성과 명확성을 위해서는 훨씬 유용할 것 같다는 생각이 들어서 수정하게 되었다
수정된 OperatorType
- calculate 메서드를 추상 메서드로 선언 후 각각의 연산자 타입에서 오버라이딩 하여 다르게 구현
package com.example.calculator3;
import com.example.common.exception.DivideByZeroException;
// 연산자 및 해당 연산자에 해당하는 연산메서드를 선언한 enum class
public enum OperatorType {
PLUS("+") {
@Override
public <T extends Number> double calculate(T firstInput, T secondInput) {
return firstInput.doubleValue() + secondInput.doubleValue();
}
},
MINUS("-") {
@Override
public <T extends Number> double calculate(T firstInput, T secondInput) {
return firstInput.doubleValue() - secondInput.doubleValue();
}
},
MULTIPLY("*") {
@Override
public <T extends Number> double calculate(T firstInput, T secondInput) {
return firstInput.doubleValue() * secondInput.doubleValue();
}
},
DIVIDE("/") {
@Override
public <T extends Number> double calculate(T firstInput, T secondInput) throws DivideByZeroException {
if (secondInput.doubleValue() == 0) {
throw new DivideByZeroException();
}
return firstInput.doubleValue() / secondInput.doubleValue();
}
};
private final String operator;
OperatorType(String operator) {
this.operator = operator;
}
//계산을 수행하는 메서드를 추상메서드로 선언하여 각각의 연산자 객체가 오버라이딩하여 구현
public abstract <T extends Number> double calculate(T firstInput, T secondInput) throws DivideByZeroException;
}
public class ArithmeticCalculator {
private List<Double> results = new ArrayList<>();
public <T extends Number> Double calculate(T firstInput, T secondInput, String operator) throws DivideByZeroException {
double answer = switch (operator) {
case "+" -> OperatorType.PLUS.calculate(firstInput, secondInput);
case "-" -> OperatorType.MINUS.calculate(firstInput, secondInput);
case "*" -> OperatorType.MULTIPLY.calculate(firstInput, secondInput);
case "/" -> OperatorType.DIVIDE.calculate(firstInput, secondInput);
default -> throw new IllegalArgumentException("Invalid operator: " + operator);
};
results.add(answer);
return answer;
}
}
예외처리 추가
- 잘못 입력받은 연산자 값과 피연산자 값, 0으로 나눈 경우의 예외 처리 클래스를 생성
- ArithmeticCalculator에 입력값 예외처리에 대한 내용을 넣기에는 ArithmeticCalculator의 책임이 커지는 것 같다고 생각했기에 Parser를 생성하여 Parser객체에서 입력값에 대한 예외처리에 대한 내용을 처리하도록 책임을 분리
- ArithmeticCalculator에서는 연산 수행과 관련된 예외 처리만 수행하도록 함
/*
* 입력값을 검증하는 class, ArithmeticCalculator에 입력값 검증까지 포함하면 책임이 너무 커지기에 분리
*/
public class Parser {
private static final String OPERATION_REG = "[+\\-*/]";
private static final String NUMBER_REG = "^[0-9]*$";
private String firstInput;
private String secondInput;
private String operator;
private final ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculator();
public ArithmeticCalculator getArithmeticCalculator() {
return arithmeticCalculator;
}
//입력받은 피연산자가 숫자가 아닌 경우룰 처리하는 예외 처리 메서드
public void validateInputNumbers(String firstInput, String secondInput) throws BadInputException {
if (!Pattern.matches(NUMBER_REG, firstInput) || !Pattern.matches(NUMBER_REG, secondInput)) {
throw new BadInputException("숫자타입");
}
setFirstInput(firstInput);
setSecondInput(secondInput);
}
//입력받은 연산자가 사칙연산자에서 벗어난 경우룰 처리하는 예외 처리 메서드
public void validateOperator(String operator) throws InvalidOperatorException{
if (!Pattern.matches(OPERATION_REG, operator)) {
throw new InvalidOperatorException();
}
setOperator(operator);
}
//필드로 가지고 있는 ArithmeticCalculator를 호출하여 연산을 수행
public Double executeCalculator() throws DivideByZeroException {
// 여기서 String 타입의 피연산자들을 실수형이나 정수형으로 변환하여 자유롭게 넣어 줄 수 있음, Integer도 가능
Double firstNumber = Double.parseDouble(firstInput);
Double secondNumber = Double.parseDouble(secondInput);
return arithmeticCalculator.calculate(firstNumber, secondNumber, operator);
}
public void setFirstInput(String firstInput) {
this.firstInput = firstInput;
}
public void setSecondInput(String secondInput) {
this.secondInput = secondInput;
}
public void setOperator(String operator) {
this.operator = operator;
}
}
public class ArithmeticCalculator {
private List<Double> results = new ArrayList<>();
public <T extends Number> Double calculate(T firstInput, T secondInput, String operator) throws DivideByZeroException {
double answer = switch (operator) {
case "+" -> OperatorType.PLUS.calculate(firstInput, secondInput);
case "-" -> OperatorType.MINUS.calculate(firstInput, secondInput);
case "*" -> OperatorType.MULTIPLY.calculate(firstInput, secondInput);
case "/" -> OperatorType.DIVIDE.calculate(firstInput, secondInput);
default -> throw new IllegalArgumentException("Invalid operator: " + operator);
};
results.add(answer);
return answer;
}
}
'JAVA' 카테고리의 다른 글
객체지향적인 계산기 만들기 : 멘토님 코드와 나의 코드간의 개선점 비교 (0) | 2025.01.13 |
---|---|
제네릭 타입제한과 필드에서의 값 전달 (feat : 계산기 과제) (0) | 2025.01.13 |
Lambda & Stream을 이용하여 특정 값보다 큰 값들만 조회하기 (0) | 2025.01.09 |
제네릭을 활용한 Double타입 계산이 가능한 계산기 만들기 (0) | 2025.01.08 |
다형성을 이용한 계산기 만들기 - 예외처리 추가 (0) | 2025.01.07 |