Java에서 Getter와 Setter를 사용해야 하는 이유와 캡슐화 쉽게 이해하기
객체지향 설계
// 잘못된 방식 (외부에서 직접 접근 가능)
public class Person {
public String name;
}
// 올바른 방식 (외부에서 getter와 setter를 통해서만 접근 가능)
public class Person {
private String name; // private로 선언하여 외부 접근 차단
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
캡슐화(Encapsulation)
객체지향의 4가지 특징 중 하나인 캡슐화는 데이터(속성)와 그 데이터를 다루는 코드(기능)를 하나로 묶고, 외부에서 데이터를 함부로 바꾸지 못하게 보호하는 것입니다.
위 예제에서 보면 name이라는 변수가 데이터라고 볼 수 있습니다. getName과 setName은 데이터를 다루는 코드라고 볼 수 있습니다. 데이터와 데이터를 다루는 코드가 하나로 묶여 있습니다. 변수의 접근제어자를 private으로 선언했기 때문에 외부에서 데이터를 함부로 바꿀 수 없습니다.
변수의 접근제어자를 private으로 바꾸고, getter/setter를 만드는 이 일반적인 방법은 이 캡슐화를 하기 위함입니다.
단일 책임 원칙 (SRP)
개방 폐쇄 원칙 (OCP)
유지보수성
세밀한 데이터 접근 제어
public class ImmutablePoint {
private final int x;
public ImmutablePoint(int x) {
this.x = x;
}
public int getX() {
return x;
}
// setter 없음 -> x는 변경 불가
}
위 예제와 같이 setter를 만들지 않고, 변수에 final을 추가함으로써 최초에 입력된 값이 변경되지 않는 불변 객체도 만들 수 있습니다.
디버깅/모니터링 용이성
getter나 setter에 브레이크 포인트를 걸거나 로깅을 추가해서 디버깅과 모니터링을 더 세밀하게 할 수 있습니다.
프레임워크 및 라이브러리 호환성
Spring, Hibernate, Jackson 등이 제대로 동작하지 않을 수 있습니다.
Spring 데이터 바인딩
@RestController
public class UserController {
@PostMapping("/users")
public String createUser(@ModelAttribute User user) {
// setter가 없으면 user.username 값이 null로 남아 있음
return "username: " + user.getUsername();
}
}
Spring에서의 JSON과 Java 객체 간 변환
@RestController
public class UserRestController {
@GetMapping("/api/users/{id}")
public User getUser(@PathVariable Long id) {
User user = userService.findById(id);
// 반환 시 Jackson 라이브러리가 User 객체의 getter를 호출하여 JSON으로 변환
return user;
}
@PostMapping("/api/users")
public User createUser(@RequestBody User user) {
// JSON -> 객체 변환 시 setter 메서드 사용
return userService.save(user);
}
}
Lombok 활용
// Lombok 사용 예시
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class Person {
private String name;
private int age;
// getter/setter 코드를 직접 작성할 필요 없음
}
Lombok을 활용하면 getter/setter를 직접 작성할 필요가 없습니다. 실무에서도 많이 사용되고 있으니 적극적으로 활용해보세요.
글을 마치며
지금까지 Java에서 getter/setter를 사용해야 하는 다양한 이유를 살펴보았습니다. 단순히 관례적으로 사용하는 것이 아니라, 객체지향 설계 원칙 준수, 유지보수성 향상, 세밀한 데이터 제어, 디버깅 용이성, 그리고 프레임워크 호환성 등 실질적인 이점을 제공합니다. getter/setter를 작성하는 것이 번거롭다면, lombok 라이브러리의 @Getter, @Setter 어노테이션을 활용하여 간편하게 코드를 작성할 수 있습니다. 이를 통해 보일러플레이트 코드를 줄이면서도 객체지향의 장점을 모두 취할 수 있습니다. 효과적인 캡슐화와 적절한 getter/setter 활용으로 더 견고하고 유지보수 하기 쉬운 코드를 작성하시길 바랍니다.
댓글
댓글 쓰기