본문 바로가기
Trouble Shooting

Java 계산기 과제 - level 2 트러블슈팅

by suyeoneee 2024. 11. 20.

레벨1에서는 클래스없이 계산기 기능을 구현했다면, 레벨2에서는 클래스를 적용해서 연산을 수행할 수 있는 계산기를 만드는 단계이다.

자바 문법 강의 3주차 숙제로 이런 비슷한 계산기를 만들어봤어서 크게 어렵지는 않았다.

고민이 되었던 부분은 결과값을 저장하는 컬렉션을 어떤 걸로 선택할지였다. 컬렉션에 결과값을 저장하기도 하고, 저장된 결과값 중 가장 먼저 저장된 데이터를 삭제해야한다.

가장 먼저 저장된 데이터를 꺼내서 삭제하는 건 FIFO 식으로 데이터를 다루는 큐 Queue가 적합할 것 이라 생각했다. FIFO과 LIFO 모두 동작할 수 있는 Deque도 고려했지만 Queue를 한 번 다뤄보고싶어서 결과적으로는 Queue를 선택했다. (만약 최근 결과값에 이어서 연산할 예정이라면 deque나 stack이 필요할 듯??)

그리고 getter, setter 메서드를 추가하여 연산 결과를 저장하고 있는 컬렉션 필드에 직접 접근하지 못하도록 캡슐화하였다. getter 부분은 쉽게 작성할 수 있었지만 setter에서 기존 코드를 어떤식으로 캡슐화할지 헷갈렸었다. (아래 트러블슈팅 내용에도 적었다.)

 

 Level 2. 클래스를 적용해 기본적인 연산을 수행할 수 있는 계산기 만들기

📋 요구사항

  • 사칙연산을 수행 후, 결과값 반환 메서드 구현 & 연산 결과를 저장하는 컬렉션 타입 필드를 가진 Calculator 클래스를 생성
  • Lv 1에서 구현한 App 클래스의 main 메서드에 Calculator 클래스가 활용될 수 있도록 수정
  • App 클래스의 main 메서드에서 Calculator 클래스의 연산 결과를 저장하고 있는 컬렉션 필드에 직접 접근하지 못하도록 수정 (캡슐화)
  • Calculator 클래스에 저장된 연산 결과들 중 가장 먼저 저장된 데이터를 삭제하는 기능을 가진 메서드를 구현한 후 App 클래스의 main 메서드에 삭제 메서드가 활용될 수 있도록 수정

❕예외 처리

Level 1 트러블 슈팅 참고

2024.11.20 - [TIL] - JAVA 계산기 과제 - level 1 트러블슈팅

 

JAVA 계산기 과제 - level 1 트러블슈팅

내일배움캠프 시작 후 첫 개인 과제! 바로 계산기 프로그램을 만드는 과제가 나에게 주어졌다!이 과제에는 총 레벨3까지 있으며, 레벨1~2까지는 필수 기능을 구현하는 단계이고 레벨3은 도전 기

mon-monde.tistory.com

 

📂  FIFO 구조의 컬렉션 Queue

  • 연산 결과값 저장 .add
public void setResult(double result){
        resultQueue.add(result);
}

 

  • 연산 결과값 return LinkedList로 강제 형 변환 후 .getLast()

가장 최근에 저장된 값에 접근하기 위하여 LinkedList의 마지막 요소를 가져온다

public Double getResult(){
        return ((LinkedList<Double>) resultQueue).getLast();
}

 

  • 가장 먼저 저장된 데이터를 삭제 .peek()
public void removeResult(){
        double result = resultQueue.peek(); // 가장 먼저 저장된 데이터
        System.out.println(result + " 삭제 완료");
        resultQueue.poll(); // FIFO -> 가장 맨 아래 값을 꺼내어 삭제
}

 

🌀 트러블 슈팅

1. 문제 상황 발생

  • App 클래스의 main 메서드에서 Calculator 클래스의 연산 결과를 저장하고 있는 컬렉션 필드에 직접 접근하지 못하도록 수정 (캡슐화)
    • 간접 접근을 통해 필드에 접근하여 가져올 수 있도록 구현합니다. (Getter 메서드)
    • 간접 접근을 통해 필드에 접근하여 수정할 수 있도록 구현합니다. (Setter 메서드)
    • 위 요구사항을 모두 구현 했다면 App 클래스의 main 메서드에서 위에서 구현한 메서드를 활용 해봅니다.

요구사항 대로라면 main 메서드 안에서 getter와 setter 모두 활용해야 한다. getter는 계산 결과를 출력할 때 활용하였지만 setter는 Calculator 클래스 안에서 활용하였다. 요구사항을 제대로 잘 읽어보니 setter도 main에서 활용해야하는 것 같았다.... 

이미 다 했는데 main에서 setter를 사용하게끔 어떻게 수정을 해야하지?? 

 

Calculator.java

public void calculate(char operator, int firstNum, int secondNum) {
    if (operator == '+')
        setResult((double) firstNum + secondNum);
    else if (operator == '-')
        setResult((double) firstNum - secondNum);
    else if (operator == '*')
        setResult((double) firstNum * secondNum);
    else if (operator == '/')
        setResult((double) firstNum / secondNum);
}

public void setResult(double result) {
    resultQueue.add(result);
}

public Double getResult() {
    return ((LinkedList<Double>) resultQueue).getLast();
}

 

Main.java

// 연산자, 피연산자 입력 받은 후 계산기 실행
calculator.calculate(operator, firstNum, secondNum);
System.out.println("계산 결과: " + calculator.getResult());

 

2. 원인 추론

calculate 메서드 안에서 setter를 사용하여 컬렉션에 값을 저장하게끔 코드를 작성했는데, calculate 메서드가 연산하기, setter 이용하여 결과값 저장하기 등 역할을 여러 개 맡은 것 같다... 요구 사항대로라면 컬렉션에 값을 저장하는 건 main에서 컬렉션 간접 접근을 통해 실행돼야 하는 거 같은데 🤔

 

3. 해결 방안

calculate 메서드는 연산해주는 역할만 하도록하고, main에서 결과값을 return받으면 그것을 setter 메서드를 통해 컬렉션에 저장하자

 

Calculator.java

public Double calculate(char operator, int firstNum, int secondNum) {
    double result = 0;
    if (operator == '+') {
        result = ((double) firstNum + secondNum);
    } else if (operator == '-') {
        result = ((double) firstNum - secondNum);
    } else if (operator == '*') {
        result = ((double) firstNum * secondNum);
    } else if (operator == '/') {
        result = ((double) firstNum / secondNum);
    }
    
    return result;
}

public void setResult(double result) {
    resultQueue.add(result);
}

public Double getResult() {
    return ((LinkedList<Double>) resultQueue).getLast();
}

 

Main.java

// 계산기 실행
// 1. 입력받은 매개변수로 calculate() 메서드 실행
// 2. 반환된 결과값을 setResult()메서드를 통해 결과값 컬렉션에 추가 (setter)
calculator.setResult(calculator.calculate(operator, firstNum, secondNum));
System.out.println("계산 결과: " + calculator.getResult()); //getter

 

4. 결과 확인

수정 전과 다름없이 계산기도 잘 작동하고, 결과값도 컬렉션에 잘 저장된다. calculate 메서드가 더 깔끔해진 것 같다. 

 

챗지피티에게 수정 전 calculate 메서드에 대해 어떤지 물어보았는데 단일 책임 원칙을 위반하였다고 한다. 이 원칙은 객체지향 설계의 중요한 요소로, 하나의 메서드나 클래스는 하나의 책임만 가져야 한다는 것을 강조한다. 과제를 통해 이 중요한 요소에 대해 고찰할 수 있었다.!

댓글