반응형
캡슐화란?
**캡슐화(Encapsulation)**는 객체지향 프로그래밍의 핵심 원칙 중 하나로, 데이터와 그 데이터를 조작하는 메서드를 하나의 단위로 감싸고, 외부에서의 직접적인 접근을 제한하는 것입니다.
캡슐화의 목적
- 데이터 보호: 잘못된 값으로부터 객체의 상태를 보호
- 정보 은닉: 내부 구현 세부사항을 외부로부터 숨김
- 유지보수성 향상: 내부 구현 변경 시 외부 코드에 미치는 영향 최소화
- 코드 재사용성: 잘 설계된 캡슐화는 다른 프로젝트에서도 안전하게 재사용 가능
문제가 있는 코드
public class Time {
public int hour;
public int minute;
public int second;
}
문제점:
- 시간 값의 유효성 검사 불가능 (hour > 23, minute > 59 등)
- 외부에서 임의로 값 변경 가능
- 데이터 무결성 보장 불가
// 이런 위험한 상황이 발생할 수 있음
Time time = new Time();
time.hour = -5; // 음수 시간!
time.minute = 70; // 70분!
캡슐화를 적용한 개선된 코드
public class Time {
private int hour; // 0~23 사이의 값
private int minute; // 0~59 사이의 값
private int second; // 0~59 사이의 값
// 생성자
public Time() {
this(0, 0, 0);
}
public Time(int hour, int minute, int second) {
setHour(hour);
setMinute(minute);
setSecond(second);
}
// Getter 메서드들
public int getHour() {
return hour;
}
public int getMinute() {
return minute;
}
public int getSecond() {
return second;
}
// Setter 메서드들 (유효성 검사 포함)
public boolean setHour(int hour) {
if (isValidHour(hour)) {
this.hour = hour;
return true;
}
return false; // 설정 실패를 알림
}
public boolean setMinute(int minute) {
if (isValidMinute(minute)) {
this.minute = minute;
return true;
}
return false;
}
public boolean setSecond(int second) {
if (isValidSecond(second)) {
this.second = second;
return true;
}
return false;
}
// 전체 시간을 한 번에 설정하는 메서드
public boolean setTime(int hour, int minute, int second) {
boolean hourSet = setHour(hour);
boolean minuteSet = setMinute(minute);
boolean secondSet = setSecond(second);
return hourSet && minuteSet && secondSet;
}
// 유효성 검사 메서드들 (private)
private boolean isValidHour(int hour) {
return hour >= 0 && hour <= 23;
}
private boolean isValidMinute(int minute) {
return minute >= 0 && minute <= 59;
}
private boolean isValidSecond(int second) {
return second >= 0 && second <= 59;
}
// 시간을 문자열로 표현하는 메서드
@Override
public String toString() {
return String.format("%02d:%02d:%02d", hour, minute, second);
}
// 시간 비교 메서드
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Time time = (Time) obj;
return hour == time.hour &&
minute == time.minute &&
second == time.second;
}
}
사용 예제
public class TimeTest {
public static void main(String[] args) {
// 객체 생성 및 초기화
Time time = new Time(14, 30, 45);
System.out.println("현재 시간: " + time.toString()); // 14:30:45
// 안전한 값 설정
if (time.setHour(23)) {
System.out.println("시간 설정 성공: " + time.getHour() + "시");
}
// 잘못된 값 설정 시도
if (!time.setHour(25)) {
System.out.println("잘못된 시간 값입니다. 현재 시간: " + time.getHour() + "시");
}
// 전체 시간 설정
if (time.setTime(12, 0, 0)) {
System.out.println("정오로 설정: " + time);
}
// 객체 비교
Time noon = new Time(12, 0, 0);
if (time.equals(noon)) {
System.out.println("두 시간이 같습니다.");
}
}
}
접근 제어자의 종류와 범위
접근 제어자 같은 클래스 같은 패키지 다른 패키지의 하위클래스 다른 패키지
private | ✅ | ❌ | ❌ | ❌ |
default | ✅ | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ | ✅ |
모던 자바에서의 추가 고려사항
1. 불변 객체(Immutable Object) 사용
public final class ImmutableTime {
private final int hour;
private final int minute;
private final int second;
public ImmutableTime(int hour, int minute, int second) {
if (!isValidTime(hour, minute, second)) {
throw new IllegalArgumentException("잘못된 시간 값입니다.");
}
this.hour = hour;
this.minute = minute;
this.second = second;
}
// Getter만 제공, Setter는 없음
public int getHour() { return hour; }
public int getMinute() { return minute; }
public int getSecond() { return second; }
// 값을 변경하려면 새로운 객체를 반환
public ImmutableTime withHour(int newHour) {
return new ImmutableTime(newHour, this.minute, this.second);
}
private boolean isValidTime(int h, int m, int s) {
return h >= 0 && h <= 23 && m >= 0 && m <= 59 && s >= 0 && s <= 59;
}
}
2. Java 14+ Record 사용 (간단한 데이터 클래스)
public record TimeRecord(int hour, int minute, int second) {
// 생성자에서 유효성 검사
public TimeRecord {
if (hour < 0 || hour > 23) {
throw new IllegalArgumentException("시간은 0-23 사이여야 합니다.");
}
if (minute < 0 || minute > 59) {
throw new IllegalArgumentException("분은 0-59 사이여야 합니다.");
}
if (second < 0 || second > 59) {
throw new IllegalArgumentException("초는 0-59 사이여야 합니다.");
}
}
@Override
public String toString() {
return String.format("%02d:%02d:%02d", hour, minute, second);
}
}
핵심 원칙
- 필드는 private으로: 직접 접근을 막고 메서드를 통한 제어된 접근만 허용
- 유효성 검사: setter 메서드에서 항상 입력값의 유효성을 검사
- 적절한 반환값: 설정 성공/실패를 boolean으로 반환하거나 예외 발생
- 최소 권한 원칙: 필요한 최소한의 접근 권한만 부여
- 일관성 유지: 객체의 상태가 항상 유효하도록 보장
캡슐화는 단순히 필드를 숨기는 것이 아니라, 객체의 무결성을 보장하고 외부와의 안전한 인터페이스를 제공하는 핵심 개념입니다.
반응형
'자바의 정석' 카테고리의 다른 글
매개변수의 다형성 (0) | 2022.08.22 |
---|---|
상속 (0) | 2022.05.23 |
인스턴스 멤버와 정적 멤버 (0) | 2022.04.15 |
메소드 Method (0) | 2022.04.12 |
생성자 Constructor (0) | 2022.04.12 |