012. 지역함수와 확장

지역함수와 확장

많은 개발자들은 코드의 중복이 최소화되어야만 좋은 코드라고 생각하고 있다.

하지만 중복을 최소화하기 위한 chunk의 생산이 오히려 구조를 파악하기 더 힘들게 만들 때가 있다.

이를 해결하기 위해 코틀린은 지역 함수에서의 확장을 지원한다.

아래의 예제를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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")
}
// Save user to the database
}

/* 출력 결과 */
>>> saveUser(User(1, "", ""))
java.lang.IllegalArgumentException: Can't save user 1: empty Name

위의 코드에서 중복되는 부분을 확인할 수 있을 것이다.

유효성 검사를 위한 validate() 함수를 사용해 중복을 제거해보자.

1
2
3
4
5
6
7
8
9
10
11
12
class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
fun validate(user: User, value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: empty $fieldName")
}
}
validate(user, user.name, "Name")
validate(user, user.address, "Address")
// Save user to the database
}

이제 좀 더 좋은 코드가 되었다.

유효성 검증 로직이 중복되지 않으며, 필드의 추가도 쉽게 대응할 수 있다.

하지만 데이터를 검증하기 위해 해당 데이터가 들어있는 객체를 넘기는 것은 우아한 방법이 아니다.

객체를 넘기지 않고 유효성을 검사할 수 있도록 개선해보자.

1
2
3
4
5
6
7
8
9
10
11
12
class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: " + "empty $fieldName")
}
}
validate(user.name, "Name")
validate(user.address, "Address")
// Save user to the database
}

최대한 개선한 것처럼 보이지만, 좀 더 개선하기 위해 검증 로직을 유저 객체의 확장 기능으로 추가해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class User(val id: Int, val name: String, val address: String)

fun User.validateBeforeSave() {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user $id: empty $fieldName")
}
}
validate(name, "Name")
validate(address, "Address")
}

fun saveUser(user: User) {
user.validateBeforeSave()
// Save user to the database
}

validateBeforeSave()User클래스의 지역 함수로 확장하여 좀 더 우아하게 처리할 수 있게 되었다.