TIL 계산기 level-2 구현

Seo_Thousand_Won·2024년 4월 26일

TIL

목록 보기
7/16

level_2

Github branch Level2 바로가기

기능

  1. 사용자로부터 사칙연산 또는 원의 넓이 선택 여부 입력
  2. 입력값에 결과는 이전 결과를 삭제하지 않고 저장
  3. 사용자로부터 "inquiry" 입력 시 저장 결과 전체 출력
  4. 사용자로부터 "remove" 입력 시 가장 먼저 입력한 값 삭제 ( 사칙 연산만 가능 )
  5. 사용자로부터 "exit" 입력 시 프로그램 종료
  6. 사용자의 잘못 된 입력에 대한 예외 처리
    • 정수 입력이 아닌 경우
    • 사칙연산 기호에 맞지 않는 입력인 경우
    • 나누기의 경우 두 번째로 입력한 정수가 0인 경우
    • 원의 넓이를 구하는 경우에서 입력 값 0이거나 0보다 작은 경우

App.java

public class App {
    static Scanner sc = new Scanner(System.in);

    public static void main(String[] args) {
        //Calculator 생성
        ArithmeticCalculator<Double> arithmeticCalculator = new ArithmeticCalculator<>();
        CircleCalculator circleCalculator = new CircleCalculator();

        String flag = "";
        while (!flag.equals("exit")) {
            //작업 수행 입력
            System.out.println("어떤 작업을 수행하시겠습니까? [사칙연산], [원의 넓이]");
            boolean isValid = switch (sc.nextLine().trim()) {
                case "사칙연산" -> toArithmetic(arithmeticCalculator);
                case "원의 넓이" -> toCircle(circleCalculator);
                default -> {
                    System.out.println("잘못된 입력입니다. \"사칙연산\" 또는 \"원의 넓이\" 를 입력해주세요\n");
                    yield false;
                }
            };

            if (isValid) {
                System.out.println("계산하시겠습니까? (exit 입력 시 종료)");
                flag = sc.nextLine().trim();
            }
        }
    }

    //[사칙연산]
    private static boolean toArithmetic(ArithmeticCalculator arithmeticCalculator) {
        System.out.println("사칙연산 계산기\n");
        //사칙연산에 필요한 입력
        double firstNumberInput, secondNumberInput;
        char operatorInput;
        try {
            //첫 번째 숫자
            System.out.print("첫 번째 숫자를 입력하세요: ");
            firstNumberInput = Double.parseDouble(sc.nextLine().trim());
            //두 번째 숫자
            System.out.print("두 번째 숫자를 입력하세요: ");
            secondNumberInput = Double.parseDouble(sc.nextLine().trim());

            //사용자로부터 사칙연산 기호 입력
            System.out.print("사칙연산 기호를 입력하세요: ");
            operatorInput = sc.nextLine().trim().charAt(0);
        } catch (NumberFormatException e) {
            System.out.println("잘못된 입력입니다. 숫자를 입력하세요.");
            return false;
        } catch (InputMismatchException e) {
            System.out.println(e.getMessage());
            return false;
        }

        arithmeticCalculator.toArithmeticCalculator(firstNumberInput, secondNumberInput, operatorInput);

        //연산 결과값 출력 및 저장
        double calculate;
        try {
            calculate = arithmeticCalculator.calculate();
            arithmeticCalculator.addCalculation(calculate);
            System.out.println("[사칙연산] 결과 = " + calculate + "\n");
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
            return false;
        }

        //삭제 여부 입력
        System.out.println("[사칙연산]가장 먼저 저장된 연산 결과를 삭제하시겠습니까? (remove 입력 시 삭제)");
        try {
            String removeInput = sc.nextLine().trim();
            if (removeInput.equals("remove")) {
                arithmeticCalculator.opRemoveResult();
            }
        } catch (NoSuchElementException e) {
            System.out.println(e.getMessage());
        }

        //전체 조회 여부 입력
        System.out.println("[사칙연산]저장된 연산결과를 조회하시겠습니까? (inquiry 입력 시 조회)");
        try {
            String removeInput = sc.nextLine().trim();
            if (removeInput.equals("inquiry")) {
                arithmeticCalculator.opInquiryResults(calculate);
            }
        } catch (NoSuchElementException e) {
            System.out.println(e.getMessage());
        }
        return true;
    }

    //[원의 넓이]
    private static boolean toCircle(CircleCalculator circleCalculator) {
        System.out.println("원의 넓이 계산기\n");

        double radius;
        try {
            //사용자로부터 반지름 입력
            System.out.print("반지름을 입력하세요: ");
            radius = Double.parseDouble(sc.nextLine().trim());
        } catch (NumberFormatException e) {
            System.out.println("잘못된 입력입니다. 숫자를 입력하세요.");
            return false;
        }

        circleCalculator.toCircleCalculator(radius);

        //원의 넓이 구한 후 출력 및 저장 후 전체 조회
        try {
            double area = circleCalculator.calculate();
            circleCalculator.addCalculation(area);
            System.out.println("[원의 넓이]결과 = " + area + "\n");
            circleCalculator.opInquiryResults();
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
            return false;
        } catch (NoSuchElementException e) {
            System.out.println(e.getMessage());
        }
        return true;
    }
}

ArithmeticCalculator.java

@NoArgsConstructor
public class ArithmeticCalculator<T extends Number> extends Calculator {

    private T firstNumber;
    private T secondNumber;
    private char operator;

    //연산 수행
    @Override
    double calculate() {
        double result = 0;
        if (Objects.equals(OperatorType.OPERATOR_ADD.getOperatorName(), operator)) {
            result = new AddOperator().operate((double) firstNumber, (double) secondNumber);
        } else if (Objects.equals(OperatorType.OPERATOR_SUBTRACT.getOperatorName(), operator)) {
            result = new SubtractOperator().operate((double) firstNumber, (double) secondNumber);
        } else if (Objects.equals(OperatorType.OPERATOR_MULTIPLY.getOperatorName(), operator)) {
            result = new MultiplyOperator().operate((double) firstNumber, (double) secondNumber);
        } else if (Objects.equals(OperatorType.OPERATOR_DIVIDE.getOperatorName(), operator)) {
            result = new DivideOperator().operate((double) firstNumber, (double) secondNumber);
        } else if (Objects.equals(OperatorType.OPERATOR_MOD.getOperatorName(), operator)) {
            result = new ModOperator().operate((double) firstNumber, (double) secondNumber);
        } else {
            throw new IllegalArgumentException("[ +, -, /, *, % ] 이외에 입력되었습니다.");
        }
        return result;
    }

    //필드값 주입
    public void toArithmeticCalculator(T firstNumberInput, T secondNumberInput, char operatorInput) {
        this.firstNumber = firstNumberInput;
        this.secondNumber = secondNumberInput;
        this.operator = operatorInput;
    }

    //가장 먼저 저장된 결과값 삭제
    public void opRemoveResult() {
        if (getResults().isEmpty()) {
            throw new NoSuchElementException("삭제할 연산 결과가 없습니다.");
        }
        System.out.println("remove = " + getResults().poll());
    }

    //저장된 결과값 전체 조회
    public void opInquiryResults(double num) {
        if (getResults().isEmpty()) {
            throw new NoSuchElementException("조회할 연산 결과가 없습니다.");
        }

        getResults().stream()
                .filter(result -> result > num)
                .forEach(System.out::println);
    }

}

CircleCalculator.java

import java.util.NoSuchElementException;

public class CircleCalculator extends Calculator {
    private final static double PI = 3.14159265358979323846;
    private double radius;

    public CircleCalculator() {
    }

    //필드값 주입
    public void toCircleCalculator(double radius) {
        this.radius = radius;
    }

    //연산 수행
    @Override
    double calculate() {
        if (radius <= 0) {
            throw new IllegalArgumentException("반지름은 양수여야 합니다.");
        }
//      return radius * radius * Math.PI;
        return radius * radius * PI;
    }

    //저장된 결과값 전체 조회
    @Override
    void opInquiryResults() {
        if (getResults().isEmpty()) {
            throw new NoSuchElementException("조회할 연산 결과가 없습니다.");
        }

        int index = 1;
        for (Double result : getResults()) {
            System.out.println(index + "번째 결과는 = " + result);
            index++;
        }
    }

}

Operator.java

public interface Operator {
    double operate(double firstNum, double secondNum);
}

AddOperator.java

public class AddOperator implements Operator{
    @Override
    public double operate(double firstNum, double secondNum) {
        return firstNum + secondNum;
    }
}

SubStractOperator.java

public class SubtractOperator implements Operator {
    @Override
    public double operate(double firstNumber, double secondNumber) {
        return firstNumber - secondNumber;
    }
}

MultiplyOperator.java

public class MultiplyOperator implements Operator {

    @Override
    public double operate(double firstNumber, double secondNumber) {
        return firstNumber * secondNumber;
    }
}

DivideOperator.java

public class DivideOperator implements Operator {

    @Override
    public double operate(double firstNumber, double secondNumber) {
        if (secondNumber == 0) {
            throw new IllegalArgumentException("나눗셈 연산에서 분모(두 번째 정수)에 0이 입력될 수 없습니다.");
        }
        return firstNumber / secondNumber;
    }
}

ModOperator.java

public class ModOperator implements Operator {
    @Override
    public double operate(double firstNum, double secondNum) {
        if (secondNum == 0) {
            throw new IllegalArgumentException("나머지 연산에서 분모(두 번째 정수)에 0이 입력될 수 없습니다.");
        }
        return firstNum % secondNum;
    }
}

문제점

ArithmeticCalculator에서 사칙연산 기호를 문자가 아닌 Enum 타입으로 변경할 수 있다.
App에 사칙연산과 원의 넓이를 구하는 구현 코드가 메서드로 분리되어 있지만
많은 코드들이 담겨 있다.

0개의 댓글