コードの切り取り:ローカル関数と展開

2867 ワード

コトリンでは,関数から抽出した関数を元の関数の内部に重ねることができる.
これにより、文法的付加費用を増やさずに、コードを簡潔に整理することができる.
ローカル関数で一般的なコード重複を解消する方法を熟知するためには、これが必要です.
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를 데이터베이스에 저장한다.
}

-> saveUser(User(1, "", ""))
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를 데이터베이스에 저장한다.
}
検証ロジックの重複は消え、必要に応じてユーザーの他のフィールドの検証も簡単に追加できます.(ユーザーにさらにパラメータを追加するだけ)
ローカル関数は、その属する外部関数のすべてのパラメータと変数を使用できます.
この性質を用いて不要なユーザパラメータを除去する.
class User(val id:Int, val name: String, val address: String)

fun saveUser(user: User) {
	fun validate(value: String, fieldName: String) { // 이제 saveUser 함수의 user 파라미터를 중복 사용하지 않는다.
    	if(value.isEmpty()) {
        	throw IllegalArgumentException(
            	"Can't save user ${user.id} : " +   // 바깥 함수의 파라미터에 직접 접근 가능
                	+ "empty $fieldName")
        }
    }
    
    validate(user.name, "Name")
    validate(user.address, "Address")
    
    // user를 데이터베이스에 저장한다.
}
次に、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") // User의 프로퍼티 직접 사용 가능
        }
    }
    
    validate(name, "Name")
    validate(address, "Address")
}

fun saveuser(user: User) {     // 확장 함수 호출
	user.validateBeforeSave()
    
    // user를 데이터베이스에 저장한다.
}
拡張関数をローカル関数として定義することもできます.ユーザです.validateBeforeSaveをローカル関数としてsaveUserの内部に配置できます.
しかし,オーバーラップ関数の深さが深まると,コードの可読性は低下する.
一般的には、1つのステップの関数だけを重畳することをお勧めします.