Java
자바 - 캡슐화
상상모음
2025. 2. 18. 16:59
캡슐화(Encapsulation)란?
캡슐화(Encapsulation)는 데이터(필드)와 이를 조작하는 메서드(기능)를 하나로 묶고, 외부에서 직접 접근하지 못하도록 하는 객체 지향 프로그래밍(OOP)의 중요한 개념이야.
캡슐화의 주요 목적
- 데이터 보호 → 직접 접근을 제한하여 잘못된 값이 설정되지 않도록 함
- 정보 은닉(Information Hiding) → 내부 구현을 숨기고 외부에는 필요한 기능만 제공
- 유지보수성 향상 → 내부 로직이 변경되더라도 외부 코드에 영향을 주지 않음
- 객체의 일관성 유지 → 유효하지 않은 데이터가 설정되지 않도록 보장
캡슐화의 핵심 원칙
접근 제어자(Access Modifiers) 사용
자바에서는 private, protected, public, default(생략 가능) 같은 접근 제어자를 사용해서 클래스 내부의 데이터 접근을 제한해.
접근 제어자같은 클래스같은 패키지상속 관계 (다른 패키지)모든 곳
| private | ✅ | ❌ | ❌ | ❌ |
| default (아무것도 안 씀) | ✅ | ✅ | ❌ | ❌ |
| protected | ✅ | ✅ | ✅ | ❌ |
| public | ✅ | ✅ | ✅ | ✅ |
캡슐화 예제 코드
잘못된 예제 (캡슐화 X)
class Person {
String name;
int age;
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
person.name = "Alice";
person.age = -5; // ❌ 잘못된 값 설정 가능!
System.out.println(person.name + ", " + person.age);
}
}
문제점:
- age 값이 -5처럼 비정상적인 값이 들어갈 수도 있음 → 데이터 보호 X
- name, age 필드를 누구나 변경 가능 → 정보 은닉 X
캡슐화 적용 (Getter & Setter 활용)
class Person {
private String name;
private int age;
// 생성자
public Person(String name, int age) {
this.name = name;
setAge(age); // 유효성 검사 적용
}
// Getter (읽기)
public String getName() {
return name;
}
public int getAge() {
return age;
}
// Setter (쓰기)
public void setAge(int age) {
if (age > 0) { // 나이의 유효성 검사
this.age = age;
} else {
System.out.println("나이는 0보다 커야 합니다.");
}
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice", 25);
System.out.println(person.getName() + ", " + person.getAge());
person.setAge(-5); // ❌ "나이는 0보다 커야 합니다." 출력
System.out.println(person.getName() + ", " + person.getAge()); // 변경되지 않음
}
}
개선된 점:
- private 접근 제한자로 직접 접근 차단
- setAge()를 통해 유효한 값만 설정 가능 → 데이터 보호
- getName(), getAge()를 통해 외부에서는 안전하게 읽기 가능
불변 객체 (Immutable Object)
캡슐화의 한 형태로, 한 번 생성된 객체의 값이 변경되지 않도록 불변 객체(Immutable Object) 를 만들 수도 있어.
- final 키워드를 사용하여 필드를 수정 불가능하게 함
- Setter 메서드를 제공하지 않음
불변 객체 예제
final class ImmutablePerson {
private final String name;
private final int age;
public ImmutablePerson(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class Main {
public static void main(String[] args) {
ImmutablePerson person = new ImmutablePerson("Alice", 25);
System.out.println(person.getName() + ", " + person.getAge());
// person.age = 30; // ❌ 오류 발생 (변경 불가능)
}
}
이점:
- 필드를 final로 설정해 객체가 한 번 생성되면 변경되지 않도록 보장
- 멀티스레드 환경에서도 안전 (동시 접근 문제 방지)
캡슐화와 스프링 프레임워크에서의 활용
캡슐화는 스프링 프레임워크에서 매우 중요하게 사용돼!
- 빈(Bean)의 필드 보호 → private 필드 + @Autowired
- DTO, VO 패턴 사용 → 데이터 전송 시 직접 수정 불가
- 서비스 계층에서 로직 보호 → 불필요한 외부 접근 방지
예제: 스프링에서 캡슐화 활용 (DTO + Service)
// DTO (Data Transfer Object) → 데이터만 가지고 있음 (캡슐화)
public class UserDTO {
private String username;
private int age;
public UserDTO(String username, int age) {
this.username = username;
this.age = age;
}
public String getUsername() {
return username;
}
public int getAge() {
return age;
}
}
// Service (비즈니스 로직 담당, 캡슐화)
@Service
public class UserService {
public void registerUser(UserDTO user) {
if (user.getAge() < 18) {
throw new IllegalArgumentException("18세 이상만 가입 가능합니다.");
}
System.out.println(user.getUsername() + "님 회원가입 완료!");
}
}
// Controller (외부 요청 처리)
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("/register")
public ResponseEntity<String> registerUser(@RequestBody UserDTO user) {
try {
userService.registerUser(user);
return ResponseEntity.ok("가입 성공");
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
}
스프링에서 캡슐화를 적용한 이유:
- DTO(UserDTO): 데이터를 보호하고 직접 수정할 수 없도록 private 필드 사용
- Service(UserService): 비즈니스 로직을 감추고 데이터 유효성 검증을 캡슐화
- Controller(UserController): Service를 통해서만 데이터 처리
캡슐화를 잘 활용하는 팁
✅ 무조건 private 필드를 사용하고, 필요한 경우만 public 메서드 제공
✅ 데이터 보호를 위해 Getter & Setter에 유효성 검증 추가
✅ DTO, VO 패턴을 사용하여 캡슐화 유지
✅ 스프링 서비스 계층에서 직접 필드 접근을 제한하고 메서드만 호출하도록 구성
✅ 불변 객체(Immutable Object)를 적극 활용
결론
캡슐화는 데이터 보호와 유지보수성을 높이는 가장 기본적이면서도 강력한 개념!
특히, 스프링 프로젝트에서는 DTO, 서비스 계층에서 필수적으로 사용되므로, 실무에서도 꼭 적용