JAVA 계산기 만들기 Lv.3

SJ.CHO·2024년 9월 9일

필수기능

사용기술

  • Java
  • Git, Github

진행과정

  • Enum Class 생성 및 적용

// 연산자 enum 클래스 화
enum OperatorType {
    ADD("+"),
    SUB("-"),
    MULT("*"),
    DIV("/"),
    REM("%");

    // 프로그램이 실행되면 Map을 캐싱해 찾고자 하는 키값과 필드값을 매칭
    private static final Map<String, OperatorType> OPERATOR_MAP =
            Collections.unmodifiableMap(Stream.of(values()).collect(Collectors.toMap(OperatorType::getOperator, Function.identity())));
    private final String operator;

    // 생성자를 통한 String 매칭
    OperatorType(String operator) {
        this.operator = operator;
    }

    // 입력된 연산자를 통해 Map 안에서 열거 객체 리턴
    public static OperatorType find(String operator) {
        if (OPERATOR_MAP.containsKey(operator)) {
            return OPERATOR_MAP.get(operator);
        }
        //연산자 외 문자 입력시 예외 발생 유도
        throw new IllegalArgumentException("맞지 않는 연산자 입력 : " + operator);
    }

    public String getOperator() {
        return operator;
    }
}
public double calculate(T firstNum, T secondNum, String operator) throws ArithmeticException, OperatorInputException {
        operatorType = OperatorType.find(operator);
        switch (operatorType) {
            case ADD:
                result = firstNum.doubleValue() + secondNum.doubleValue();
                // 연산 과정 및 결과 저장 메서드 호출.
                saveCalculationProcess(firstNum, secondNum, result, operator);
                break;
            case SUB:
                result = firstNum.doubleValue() - secondNum.doubleValue();
                saveCalculationProcess(firstNum, secondNum, result, operator);
                break;
            case MULT:
                result = firstNum.doubleValue() * secondNum.doubleValue();
                saveCalculationProcess(firstNum, secondNum, result, operator);
                break;
            case DIV:
                // 분모가 0일경우 예외 발생 유도.
                if (secondNum.doubleValue() == 0 || secondNum.doubleValue() == 0.0) {
                    throw new ArithmeticException("0으로는 나눌 수 없습니다.");
                }
                result = firstNum.doubleValue() / secondNum.doubleValue();
                saveCalculationProcess(firstNum, secondNum, result, operator);
                break;
            case REM:
                result = firstNum.doubleValue() % secondNum.doubleValue();
                saveCalculationProcess(firstNum, secondNum, result, operator);
                break;
        }
        return result;
    }
  • 연산자를 단순히 Stirng 으로만 구분하는 것이 아닌 enum 클래스로 만들어 열거상수를 통해 관리하도록 변경.
  • 필드값을 통해 열거상수를 반환받기 위해 static 키워드를 통해 프로그램이 실행될 때 람다,스트림을 활용하여 Map<'필드명',열거상수 객체>로 매핑하였다.
  • 이후 입력이 들어올때마다 find()메소드를 통해 key값을 비교해 열거객체 리턴 및 활용.

참조 :
https://itellyhood.tistory.com/70
https://velog.io/@ljinsk3/Enum%EC%9D%98-%EC%9A%94%EC%86%8C%EB%A5%BC-%EC%A1%B0%ED%9A%8C%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EB%B9%84%EA%B5%90-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C-vs-HashMap

  • 피연산자 입력 제네릭화

public class ArithmeticCalculator<T extends Number> {
    private double result = 0;
    // 연산과정 및 결과 저장 List 생성
    private ArrayList<T> firstNumbers = new ArrayList<>();
    private ArrayList<T> secondNumbers = new ArrayList<>();
 public double calculate(T firstNum, T secondNum, String operator) throws ArithmeticException, OperatorInputException {
        operatorType = OperatorType.find(operator);
        switch (operatorType) {
            case ADD:
                result = firstNum.doubleValue() + secondNum.doubleValue();
                // 연산 과정 및 결과 저장 메서드 호출.
                saveCalculationProcess(firstNum, secondNum, result, operator);
                break;
 private void saveCalculationProcess(T firstNumber, T secondNumber, double result, String operator) {
        firstNumbers.add(firstNumber);
        secondNumbers.add(secondNumber);
        results.add(result);
        operators.add(operator);
    }
  • 제네릭 조건을 Number를 상속받는 하위클래스만 Type T에 대입될수 있도록 적용. 이후 숫자가 들어오는것은 확정이기에 double 형태로 변환,연산 하였다.

참조 :
https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EC%A0%9C%EB%84%A4%EB%A6%ADGenerics-%EA%B0%9C%EB%85%90-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%B3%B5%ED%95%98%EA%B8%B0
https://codevang.tistory.com/165
https://notbusyperson.tistory.com/43

  • Lambda & Stream 을 활용한 기능 추가

 // 입력값보다 큰값 출력, 스트림,람다식 사용
    public void getInputLargerThanContent(double baseValue) {
        System.out.println(baseValue + " 보다 큰 값은");
        results.stream().filter(result -> baseValue < result).forEach(System.out::println);
        System.out.println("입니다.");
    }
// 결과 리스트의 평균값 리턴
    public double getAvg() throws EmptyListException {
        if (emptyListChecker()) {
            throw new EmptyListException("저장된 결과값이 없습니다.");
        } else {
            return results.stream().filter(Objects::nonNull).mapToDouble(Double::doubleValue).average().orElse(0);
        }
    }
// 결과 리스트중 최댓값 리턴
    public double getMax() throws EmptyListException {
        if (emptyListChecker()) {
            throw new EmptyListException("저장된 결과값이 없습니다.");
        } else {
            return results.stream().filter(Objects::nonNull).mapToDouble(Double::doubleValue).max().orElse(0);
        }
    }
// 결과 리스트중 최솟값 리턴
    public double getMin() throws EmptyListException {
        if (emptyListChecker()) {
            throw new EmptyListException("저장된 결과값이 없습니다.");
        } else {
            return results.stream().filter(Objects::nonNull).mapToDouble(Double::doubleValue).min().orElse(0);
        }
  • double 값을 입력받아 자신보다 큰값을 filter(result -> baseValue < result)메소드로 거른뒤 foreach 문을 통해 출력하는 메소드.
  • Stream 은 자주 사용해보지 않았는데 익명객체와 마찬가지로 1회용객체의 형태로 출력위주의 용도로는 좋은거같다.

참조 :
https://mangkyu.tistory.com/114
https://mong-dev.tistory.com/28
https://www.elancer.co.kr/blog/view?seq=255

트러블 슈팅

링크(클릭)

구현기능

프로그램 주요 플로우 차트

  • Main Flow

    계산기 Main
  • result index remove Flow

    계산기 index 삭제

프로그램 동작 화면

Stacks

Architecture

📦 
├─ .gitignore
├─ .idea
│  ├─ .gitignore
│  ├─ material_theme_project_new.xml
│  ├─ misc.xml
│  ├─ modules.xml
│  ├─ uiDesigner.xml
│  └─ vcs.xml
├─ CalculatingMachineProject.iml
├─ gitmessage.txt
└─ src
   └─ com
      └─ calculator
         ├─ lv1 : Lv.1 제약으로 구현한 계산기
         │  └─ Calculator.java 
         ├─ lv2 : Lv.2 제약으로 구현한 계산기
         │  ├─ App.java : main 실행 class
         │  ├─ Calculator.java : 계산 담당 Class
         │  ├─ ServiceManager.java : 프로그램 흐름 제어 class
         │  └─ customexception : 커스텀 예외
         │     ├─ EmptyListException.java
         │     └─ OperatorInputException.java
         └─ lv3: Lv.3 제약으로 구현한 계산기
            ├─ AbstractCalculator.java : 계산기능 추상 Class
            ├─ AddCalculator.java
            ├─ App.java : main 실행 class
            ├─ ArithmeticCalculator.java : 계산 흐름 담당 및 추가기능 담당 Class
            ├─ CalculatorManager.java : 계산기능구현 Class 관리 Class
            ├─ DivCalculator.java
            ├─ MultCalculator.java
            ├─ RemCalculator.java
            ├─ ServiceManager.java : 프로그램 흐름 제어 Class
            ├─ SubCalculator.java
            └─ customexception
               ├─ EmptyListException.java
               └─ OperatorInputException.java

Github 링크

: https://github.com/seongjun1130/CalculatingMachineProject

profile
70살까지 개발하고싶은 개발자

0개의 댓글