Kotlin
[Kotlin in Action] 12. 로컬함수 확장 (코드 리팩토링, 로컬함수, 중첩함수)
LearnerKSH
2022. 5. 20. 12:24
728x90
반응형
로컬함수 확장
예제 : 데이터베이스에 사용자 객체를 저장하기전, 각 필드의 validation 을 검증하는 로직
1단계. 코드 중복을 보여주는 예제
class User(val id: Int, val name: String, val address: String)
fun saveUser(user: User) {
if (user.name.isEmpty()) {
throw IllegalArgumentException (
"Can't save User ${user.id}: empty Name"
)
}
if (user.address.isEmpty()) {
throw IllegalArgumentException (
"Can't save User ${user.id}: empty Address"
)
}
}
fun main() {
saveUser(User(1, "", ""))
}
2단계. 코드 중복 줄이기
class User_2(val id: Int, val name: String, val address: String)
fun saveUser2(user: User) {
// 한 필드를 검증하는 로컬 함수를 정의한다.
fun validate(user: User,
value: String,
fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException (
"Can't save user ${user.id}: empty $fieldName"
)
}
}
// 로컬함수를 호출해서 각 필드를 검증한다.
/* 아쉬운점 : 로컬함수에게 User 객체를 하나하나 전달해야한다. */
validate(user, user.name, "Name")
validate(user, user.address, "Address")
}
2-1) 로컬 함수를 정의했다.
fun validate(user: User,
value: String,
fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException (
"Can't save user ${user.id}: empty $fieldName"
)
}
}
2-2) 로컬 함수를 호출한다.
validate(user, user.name, "Name")
validate(user, user.address, "Address")
문제점
로컬함수에게 User 객체를 하나하나 중복으로 전달해줘야한다.
3단계. 로컬함수에서 바깥 함수의 파라미터 접근하기
class User_3(val id: Int, val name: String, val address: String)
fun saveUser3(user: User) {
fun validate(value: String,
fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException (
// 바깥 함수의 user 파라미터에 직접 접근할 수 있다.
"Can't save user ${user.id}: empty $fieldName"
)
}
}
validate(user.name, "Name")
validate(user.address, "Address")
}
3-1) 바깥 함수 saveUser3의 user 파라미터에 직접 접근할 수 있다.
fun validate(value: String,
fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException (
// 바깥 함수의 user 파라미터에 직접 접근할 수 있다.
"Can't save user ${user.id}: empty $fieldName"
)
}
}
4단계. 검증 로직을 확장 함수로 추출하기
- 함수 중첩은 한단계만 권장한다. 중첩된 함수의 깊이가 깊어지면 코드를 읽기가 어려워진다.
class User_4(val id: Int, val name: String, val address: String)
fun User.validateBeforeSave() {
fun validate(value:String, fieldName:String) {
if (value.isEmpty()) {
throw IllegalArgumentException (
// User의 프로퍼티를 직접 사용할 수 있다.
"Can't save user ${id}: empty $fieldName"
)
}
}
validate(name,"Name")
validate(address,"Address")
}
fun saveUser4(user: User) {
// 확장함수를 호출한다.
user.validateBeforeSave()
}
4-1) User의 프로퍼티를 직접 사용한다.
fun User.validateBeforeSave() {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException (
// User의 프로퍼티를 직접 사용할 수 있다.
"Can't save user ${id}: empty $fieldName"
)
}
}
...
}
4-2) 확장 함수를 호출한다.
fun saveUser4(user: User) {
// 확장함수를 호출한다.
user.validateBeforeSave()
}
반응형