getter
, setter
를 두지 않고 그냥 필드를 public
으로 선언하면 되지 않나요? 왜 그렇게 하지 않을까요?
위 질문에 대한 답을 하기 위해 알아보았다.
자바에서 필드의 값을 얻거나 필드를 초기화하기 위한 함수이다.
Kotlin에서는 자동으로 생성된다.
class Person {
var name: String? = null
get() = field // 기본 게터
set(value) {
field = value // 기본 세터
}
fun getName(): String { // 우연히 게터와 이름이 같을 뿐, 로직이 다름
return name ?: "Unknown"
}
fun fetchName(): String? { // 우연히 게터와 로직이 같을 뿐, 이름이 다름
return name
}
}
getter
, setter
를 사용하라는 주장을 확장하면 필드에 직접 접근하지 말고 메서드를 쓰라는 말과 같다. 그 이유는 필드에 접근하는 것이 캡슐화를 위반하기 때문이다.
캡슐화: 상태와 행동을 하나의 객체 안에 모으는 것
객체를 사용하면 나중에 변경될 가능성이 높은 내부 구현(특히 상태)을 외부로부터 감출 수 있다. 이를 통해 변경의 여파를 통제할 수 있다.
getter
, setter
를 통해 얻고 세팅하는 과정을 추상화하여 견고한 부분만을 공개하고, 내부적으로 어떻게 하는지에 대한 세부사항은 감출 수 있다.
질문은 원점으로 돌아온다.
*getter
, setter
도 결국 필드를 노출하는 것인데, 어떻게 캡슐화가 지켜진다고 할 수 있을까?*
이 질문은 매우 날카로운 질문이다. 다음 name
, age
의 getter
, setter
는 필드를 그대로 드러낸다.
class Person(
val name: String,
val age: Int,
)
fun main() {
val gio = Person("지오", 20)
println("안녕하세요. 저는 ${gio.name}이고, ${gio.age}살입니다.")
}
getter
, setter
를 통해 Person
의 상태를 얻어와 main
에서 자기소개를 하고 있다. 하지만 다음과 같이 제약사항이 발생한다면 어떨까?
저희 커뮤니티에서 자기소개를 할 때에는 앞으로 나이를 밝히지 않겠습니다.
이는 즉 자기소개에 대한 요구사항의 변경이다. 자기소개를 한다는 사실 자체는 변하지 않지만 자기소개에 관한 세부사항의 변경이다.
하지만 이는 Person
뿐 아니라 사용처인 main
의 수정 또한 필요로 한다.
class Person(
val name: String,
val age: Int,
)
fun main() {
val gio = Person("지오", 20)
println("안녕하세요. 저는 ${gio.name}입니다.")
}
간단한 요구사항인데도 만약 Person
의 사용처가 다양했다면 지옥이 펼쳐졌을 것이다.
하지만 캡슐화를 잘 사용했다면 다음과 같은 코드를 작성했을 것이다.
class Person(
private val name: String,
private val age: Int,
) {
fun introduce() {
println("안녕하세요. 저는 ${name}이고, ${age}살입니다.")
}
}
fun main() {
val gio = Person("지오", 20)
gio.introduce()
}
getter
, setter
를 아예 사용하지 않고 견고한 부분인 메서드만을 사용해 코드를 수행했다. 이 때 같은 제약사항이 변하면 다음과 같이 코드를 수정하면 된다.
class Person(
private val name: String,
private val age: Int,
) {
fun introduce() {
println("안녕하세요. 저는 ${name}입니다.")
}
}
fun main() {
val gio = Person("지오", 20)
gio.introduce()
}
이렇게만 보면 큰 차이가 없어 보이지만 다음에 주목해야 한다.
코드의 수정이
Person
내부에서만 일어났다.
객체의 사용처는 1곳보다 많을 가능성이 높다. 위 코드는 캡슐화의 원칙을 지켜 변경의 여파를 제한했고, 코드 수정을 최소화하는 효과를 얻는다.
getter
, setter
를 사용하지 않으면 캡슐화를 위반하기 쉽다.getter
, setter
를 사용했더라도 상태를 드러내면 캡슐화에 위반된다.→ 객체 지향 생활 체조 원칙 9. getter/setter/프로퍼티를 쓰지 않는다.
조영호, 오브젝트: 코드로 이해하는 객체지향 설계