많은 개발자들이 좋은 코드의 중요한 특징 중 하나가 중복이 없는 것이라고 믿는다.
그래서 많은 경우 메소드 추출 리팩토링을 적용해서 긴 메소드를 부분부분 나눠서 각 부분을 재활용 한다
하지만 그렇게 코드를 리팩토링하면 클래스 안에 작은 메소드가 많아지고, 각 메소드 사이의 관계를 파악하기 힘들어서 코드를 이해하기가 더 어려워질 수 있다.
또한 이 부분을 해결하고자, 추출한 메소드를 별도의 내부 클래스 안에 넣으면 코드가 깔끔하게 조직할 수는 있지만,
그에 따른 불필요한 준비 코드가 늘어난다.
코틀린에서는 더 깔끔한 해법이 존재한다.
코틀린에서는 함수에서 추출한 함수를 원 함수 내부에 중첩 시킬 수 있다.
코드 중복을 보여주는 예제
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, "", ""))
}
위 코드는 중복이 그리 많지 않다. 하지만 클래스가 사용자의 필드를 검증할 때, 필요한 여러 경우를 하나씩 처리하는 메소드로 넘쳐나기를 바라지는 않을 것이다.
로컬 함수를 사용해 코드 중복 줄이기
class User(val id : Int, val name : String, val address : String)
fun saveUser(user : User) {
fun validate(user : User, value : String, fileName : String) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id} : empty $fileName")
}
}
// 로컬 함수를 호출해서 각 필드를 검증한다.
validate(user, user.name, "Name")
validate(user, user.address, "Address")
}
위 코드로 바꾸면 검증 로직 중복이 사라졌고, User 의 다른 필드에 대한 검증도 쉽게 추가할 수 있다.
하지만, User 객체를 로컬 함수에게 하나하나 전달해야 한다는 점은 아쉽다.
다행이지만, 사실은 그럴 필요가 없다.
로컬 함수는 자신이 속한 바깥 함수의 모든 파라미터와 변수를 사용할 수 있다.
아래 코드를 확인해보자.
class User(val id : Int, val name : String, val address : String)
fun saveUser(user : User) {
// saveUser 함수의 user 파라미터를 중복 사용하지 않는다.
fun validate(value : String, fileName : String) {
if (value.isEmpty()) {
// 바깥 함수의 파라미터를 직접 접근이 가능하다.
throw IllegalArgumentException("Can't save user ${user.id} : empty $fileName")
}
}
// 로컬 함수를 호출해서 각 필드를 검증한다.
validate(user.name, "Name")
validate(user.address, "Address")
}
검증 로직을 확장 함수로 호출하기
class User(val id : Int, val name : String, val address : String)
fun User.validateBeforeSave() {
fun validate(value : String, fileName : String) {
if (value.isEmpty()) {
// User 의 프로퍼티를 직접 사용이 가능하다.
throw IllegalArgumentException("Can't save user $id : empty $fileName")
}
}
// 로컬 함수를 호출해서 각 필드를 검증한다.
validate(name, "Name")
validate(address, "Address")
}
fun saveUser(user : User) {
// 확장 함수를 호출한다.
user.validateBeforeSave()
}
User를 간결하게 유지하면서 생각해야 할 내용이 줄어 들어서 더 쉽게 코드를 파악할 수 있다.
'Language > Kotlin' 카테고리의 다른 글
[Kotlin IN ACTION] - Kotlin open / final / abstract 상속 제어(접근) 변경자 (0) | 2022.07.22 |
---|---|
[Kotlin IN ACTION] - Kotlin Interface(인터페이스) (0) | 2022.07.22 |
[Kotlin IN ACTION] - Kotlin 문자열 다루기(split) (0) | 2022.07.21 |
[Kotlin IN ACTION] - Kotlin 컬렉션 처리 (0) | 2022.07.21 |
[Kotlin IN ACTION] - Kotlin 함수 정의와 호출(확장함수) (0) | 2022.07.18 |