반응형
코틀린에서는 함수에서 추출한 함수를 원 함수 내부에 중첩시킬 수 있다. 그렇게 하면 문법적인 부가 비용을 들이지 않고 깔끔하게 코드를 조직할 수 있다. (DRY. Don't Repeat Yourself)
흔히 발생하는 코드 중복을 로컬(local)함수를 통해 어떻게 제거할 수 있는지 살펴보자.
사용자를 데이터베이스에 저장하는 함수가 있다. 이때 데이터베이스에 사용자 객체를 저장하기 전에 각 필드를 검증해야 한다.
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")
}
// user를 데이터베이스에 저장한다.
}
fun main() {
saveUser(User(1, "", ""))
}
Exception in thread "main" java.lang.IllegalArgumentException: Can't save user 1: empty Name
이런 경우 검증 코드를 로컬 함수로 분리하면 중복을 없애는 동시에 코드 구조를 깔끔하게 유지할 수 있다.
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")
// user를 데이터베이스에 저장한다.
}
fun main() {
saveUser(User(1, "", ""))
}
검증 로직 중복은 사라졌고, User의 다른 필드에 대한 검증도 쉽게 추가할 수 있다. 로컬 함수는 자신이 속한 바깥 함수의 모든 파라미터와 변수를 사용할 수 있다. 이런 성질을 이용해 불필요한 User 파라미터를 없애보자.
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")
// user를 데이터베이스에 저장한다.
}
fun main() {
saveUser(User(1, "", ""))
}
더 개선하고 싶다면 검증 로직을 User 클래스를 확장한 함수로 만들 수도 있다.
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()
// user를 데이터베이스에 저장한다.
}
fun main() {
saveUser(User(1, "", ""))
}
User.validateBeforeSave 를 saveUser 내부에 로컬 함수로 넣을 수 있지만, 중첩된 함수의 깊이가 깊어지면 코드를 읽기가 상당히 어려워진다. 따라서 일반적으로는 한 단계만 함수를 중첩시키라고 권장한다.
반응형
'프로그래밍 노트 > Kotlin' 카테고리의 다른 글
[Kotlin] 코틀린 가시성 변경자와 내부 클래스/중첩 클래스/봉인된 클래스 (0) | 2020.11.29 |
---|---|
[Kotlin] 코틀린 인터페이스와 open, final, abstract 변경자 (0) | 2020.11.29 |
[Kotlin] 코틀린 문자열과 정규식 다루기 (0) | 2020.11.24 |
[Kotlin] 코틀린 컬렉션 처리: 가변 길이 인자, 중위 함수 호출, 라이브러리 지원 (0) | 2020.11.19 |
[Kotlin] 코틀린(Kotlin) 메소드를 다른 클래스에 추가(확장 함수와 확장 프로퍼티) (0) | 2020.11.19 |