• [Kotlin In Action] 로컬 함수와 확장
    언어/Kotlin 2022. 4. 25. 00:07
    반응형

     흔히 발생하는 중복코드를 로컬 함수를 통해 어떻게 제거할 수 있는지 살펴보자.

     

    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 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.id}를 위해 user를 파라미터로 넘겨야하는 하는 점이 아쉽다. 다행이도 로컬 함수는 자신이 속한 바깥 함수의 모든 파라미터와 변수를 사용할 수 있다.

    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")
        
        // 사용자 저장
        .
        .
        .
    }

    2. 확장 함수

    위의 코드에 확장 함수를 사용하여 검증로직을 더 깔끔하게 뽑아낼 수 있다.

    class User(
        val id: Int,
        val name: String,
        val address: String,
    )
    
    fun User.validateBeforeSave() {
        fun validate(
          value: String,
          fieldName: String,
        ) {
          if (value.isEmpty()) {
            // user의 프로퍼티 직접 사용가능
            throw IllegalArgumentException("Can't save user ${this.id}: empty $fieldName")
          }
        }
        
        validate(user.name, "Name")
        validate(user.address, "Address")
    }
    
    fun saveUser(user: User) {
        
        User.validateBeforeSave() // 확장함수 호출
        
        // 사용자 저장
        .
        .
        .
    }

    3. 좀 더 나아가서 (require)

    [require 블록]을 사용하면 조금 더 가독성 좋은 코드를 작성 할 수 있다.

    class User(
        val id: Int,
        val name: String,
        val address: String,
    )
    
    fun User.validateBeforeSave() {
        fun validate(
          value: String,
          fieldName: String,
        ) {
          require(value.isEmpty()) { "Can't save user ${this.id}: empty $fieldName" }
        }
        
        validate(user.name, "Name")
        validate(user.address, "Address")
    }
    
    fun saveUser(user: User) {
        
        User.validateBeforeSave() // 확장함수 호출
        
        // 사용자 저장
        .
        .
        .
    }
    반응형

    댓글

Designed by Tistory.