이해했습니다! 이번에는 개인 프로젝트를 기반으로 작성된 내용을 블로그 형식으로 다시 정리하겠습니다. 주제를 개인 프로젝트에 맞춰 설명하겠습니다.
이번 포스트에서는 개인 프로젝트에서 발생한 문제를 해결하는 과정과, 캡슐화 원칙을 준수하는 방법을 설명하려 한다. Calculator
클래스를 사용하는 프로젝트에서 발생할 수 있는 Getter 메서드의 문제점을 알아보고, 이를 어떻게 개선할 수 있을지 다뤄보겠다.
Calculator
클래스에서 연산 결과를 저장하고, 이를 외부에서 가져오기 위해 아래와 같은 Getter 메서드를 사용하고 있었다.
public List<Double> getResults() {
return results;
}
이 메서드는 원본 results
리스트를 외부로 그대로 반환한다. 이로 인해 외부 코드에서 results
리스트를 직접 수정할 수 있는 문제가 발생할 수 있다. 예를 들어, 외부에서 getResults()
를 호출한 후, 반환된 리스트를 수정하면 원본 데이터도 변하게 된다.
List<Double> resultList = calculator.getResults();
resultList.clear(); // 원본 리스트의 데이터가 모두 삭제될 수 있음
이처럼 외부에서 리스트에 대한 직접 접근이 가능해지면, 객체의 내부 상태가 손상될 수 있다. 이러한 문제를 방지하기 위해 캡슐화의 원칙을 더 철저히 지킬 필요가 있다.
이를 해결하기 위한 방법은 간단하다. getResults()
메서드에서 원본 리스트가 아닌 복사본을 반환하여 외부에서 리스트를 수정하더라도 원본 데이터는 변하지 않도록 해야 한다.
public List<Double> getResults() {
return new ArrayList<>(results); // 복사본을 반환하여 외부에서 원본을 수정할 수 없도록 함
}
이 코드를 통해 외부에서는 리스트의 복사본을 얻기 때문에, 원본 리스트에 대한 수정이 발생하지 않는다. 이렇게 하면 데이터를 안전하게 보호할 수 있다.
package Calculator_Lv2;
import java.util.ArrayList;
import java.util.List;
public class Calculator {
// 연산 결과를 저장하는 컬렉션 타입 필드
private List<Double> results = new ArrayList<>();
// 사칙연산을 수행한 후, 결과값을 반환하는 메서드
public double calculate(int num1, int num2, char operator) {
double result = 0;
switch (operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
if (num2 == 0) {
throw new ArithmeticException("나눗셈 연산에서 두 번째 정수가 0일 수 없습니다.");
}
result = (double) num1 / num2;
break;
default:
throw new IllegalStateException("잘못된 연산 기호입니다. 다시 시도해주세요.");
}
// 결과를 리스트에 저장
results.add(result);
return result;
}
// getter - 복사본을 반환하도록 개선
public List<Double> getResults() {
return new ArrayList<>(results); // 복사본을 반환하여 원본을 보호
}
// setter - 사칙연산 수행
public void setResults(int num1, int num2, char operator) {
calculate(num1, num2, operator);
}
// 가장 먼저 저장된 데이터를 삭제하는 메서드
public void removeResults() {
if (!results.isEmpty()) {
results.remove(0);
} else {
throw new IndexOutOfBoundsException("삭제할 연산 결과가 없습니다.");
}
}
}
package Calculator_Lv2;
import java.util.InputMismatchException;
import java.util.Scanner;
public class App {
public static void main(String[] args) {
Calculator calc = new Calculator();
Scanner sc = new Scanner(System.in);
while (true) {
// Step 1 : 두 양의 정수 입력
System.out.print("첫 번째 숫자를 입력하세요: ");
int num1 = sc.nextInt();
System.out.print("두 번째 숫자를 입력하세요: ");
int num2 = sc.nextInt();
// Step 2 : 연산 기호 입력
System.out.print("사칙연산 기호를 입력하세요(+, -, *, /): ");
char operator = sc.next().charAt(0);
try {
// Step 3 : 연산 수행 및 결과 출력
calc.setResults(num1, num2, operator);
System.out.println("결과: " + calc.getResults());
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
continue;
} catch (InputMismatchException e) {
System.out.println(e.getMessage());
}
// Step 5 : exit 입력 시 종료
System.out.println("더 계산하시겠습니까? (exit 입력 시 종료)");
String nextLine = sc.next();
if (nextLine.equals("exit")) {
System.out.println("계산기를 종료합니다.");
break;
}
}
sc.close();
}
}
캡슐화는 객체 지향 프로그래밍에서 필수적인 개념이며, 데이터를 보호하고 외부로부터의 의도치 않은 수정을 방지하기 위한 중요한 기법이다. 이번 개인 프로젝트에서는 getResults()
메서드가 원본 리스트를 그대로 반환하는 문제를 발견했고, 이를 복사본을 반환하는 방식으로 개선하였다. 이러한 작은 변화가 프로젝트의 안정성과 데이터 보호에 큰 도움이 될 수 있다.