kvalidation 地址:github.com/fengzhizi71…git
它包含以下的功能:github
首先,定義一個 ValidateRule 的範型接口並使用逆變,它表示類的驗證規則。c#
能夠查看以前的文章:《Kotlin 範型之協變、逆變》 瞭解逆變。markdown
ValidateRule 包含了兩個方法:框架
interface ValidateRule<in T> { fun validate(data: T): Boolean fun errorMessage(): String } 複製代碼
而後,定義一個用於驗證類的 Validator,它繼承自 LinkedHashSet。能夠將 ValidateRule 經過 addRule() 添加到 Validator,另外 addRule() 仍是使用了infix
修飾。函數
真正的類的驗證是在 validate() 進行的,當全部的 ValidateRule 都經過時,纔算真正的驗證經過。任何一個 ValidateRule 驗證失敗,都會致使類的驗證失敗。oop
open class Validator<T> : LinkedHashSet<ValidateRule<T>>() { fun validate(data: T, onSuccess: (() -> Unit)? = null, onError: ((String) -> Unit)? = null): Boolean { forEach { if (!it.validate(data)) { onError?.invoke(it.errorMessage()) return false } } onSuccess?.invoke() return true } infix fun addRule(rule: ValidateRule<T>): Validator<T> { add(rule) return this } } 複製代碼
屬性的驗證是經過 PropertyValidator 類實現的,和以前的 Validator 無關。PropertyValidator 的主要方法包括 mustBe()、field()、fields()。this
類的屬性經過 field() 方法進行判斷,多個屬性能夠經過 fields() 方法進行判斷,而 mustBe() 方法能夠不限定任何屬性。spa
class PropertyValidator<T> ( private val validationProcessItems: MutableList<ValidationProcessItem<T>> = mutableListOf(), private val fieldNames: List<String> = emptyList()) { fun mustBe(specName: String = "", validateFunction: T.() -> Boolean): ValidationSpec<T> { val spec = ValidationSpec(specName = specName, validateFunction = validateFunction, fieldNames = fieldNames) validationProcessItems.add(spec) return spec } fun field(fieldName: String, block: PropertyValidator<T>.() -> Unit) { val fieldValidator = PropertyValidator(validationProcessItems, listOf(fieldName)) block.invoke(fieldValidator) } fun fields(vararg fieldNames: String, block: PropertyValidator<T>.() -> Unit) { val fieldValidator = PropertyValidator(validationProcessItems, fieldNames.toList()) block.invoke(fieldValidator) } ...... } 複製代碼
類的屬性也有相似的 ValidateRule。它是 ValidationSpec ,用於驗證屬性的某一條規則。設計
open class ValidationSpec<T>(specName: String = "", fieldNames: List<String>, val validateFunction: T.() -> Boolean) : ValidationProcessItem<T>(specName, fieldNames) { private var messageFunction: ((T) -> String)? = null fun errorMessage(messageFunction: T.() -> String) { this.messageFunction = messageFunction } fun showMessage(target: T) = messageFunction?.invoke(target) ?: "validation failed" fun isValid(target: T): Boolean = validateFunction(target) } 複製代碼
ValidationSpec 的 isValid() 方法用於真正的驗證,若是它返回 false 則表示該屬性不知足當前的規則。
因爲定義了一個 defineValidator()
fun <T> defineValidator(block: Validator<T>.() -> Unit): Validator<T> { val v = Validator<T>() block.invoke(v) return v } 複製代碼
所以,定義一個 Validator 很簡單,能夠在 block 中添加 ValidateRule。
val validator = defineValidator<String>{ this addRule EmailRule() } val email = "fengzhizi715@126.com" val result = validator.validate(email,onError = { println(it)}) println(result) 複製代碼
因爲 Validator 是一個 LinkedHashSet,所以能夠在 block 中添加多個 ValidateRule。
例以下面的密碼校驗,使用了兩個 ValidateRule:
val validator = defineValidator<String>{ this addRule MinLengthRule(6) // 密碼長度不能小於6位 this addRule PatternRule("^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]+$") // 密碼必須數字和字母的組合 } val password = "123456a" val result = validator.validate(password,onError = { println(it)}) println(result) 複製代碼
因爲定義了一個 RxValidator
class RxValidator<T>(private val data: T) : Validator<T>() { fun toObservable(success: (() -> Unit)? = null,error: ((String) -> Unit)? = null) = Observable.just(data) .map { validate(it, onSuccess = { success?.invoke() }, onError = { message -> error?.invoke(message) }) } fun toFlowable(success: (() -> Unit)? = null,error: ((String) -> Unit)? = null) = Flowable.just(data) .map { validate(it, onSuccess = { success?.invoke() }, onError = { message -> error?.invoke(message) }) } fun toSingle(success: (() -> Unit)? = null,error: ((String) -> Unit)? = null) = Single.just(data) .map { validate(it, onSuccess = { success?.invoke() }, onError = { message -> error?.invoke(message) }) } fun toMaybe(success: (() -> Unit)? = null,error: ((String) -> Unit)? = null) = Maybe.just(data) .map { validate(it, onSuccess = { success?.invoke() }, onError = { message -> error?.invoke(message) }) } } 複製代碼
而且定義了一個 defineRxValidator() 和擴展函數 rxValidator()
fun <T> defineRxValidator(data: T, block: RxValidator<T>.() -> Unit): RxValidator<T> { val v = RxValidator<T>(data) block.invoke(v) return v } fun <T> T.rxValidator(block: RxValidator<T>.() -> Unit): RxValidator<T> { val v = RxValidator<T>(this) block.invoke(v) return v } 複製代碼
所以 RxJava 的結合使用變得很簡單,下面分別使用兩種方式展現瞭如何結合 RxJava 的使用:
val email = "fengzhizi715@126.com" defineRxValidator(email){ this addRule EmailRule() } .toObservable( error = { println(it)}) .subscribe{ println(it) } val invalidEmail = "fengzhizi715@126" invalidEmail.rxValidator { this addRule EmailRule() } .toObservable( error = { println(it)}) .subscribe{ println(it) } 複製代碼
參考上面的代碼,在 kvalidation 中也事先定義了一個 definePropertyValidator()
fun <T> definePropertyValidator(block: PropertyValidator<T>.() -> Unit): PropertyValidator<T> { val v = PropertyValidator<T>() block.invoke(v) return v } 複製代碼
所以,在定義一個 PropertyValidator 時,也能夠在 block 中添加多個 mustBe()、field()、fields() 方法。
在 field()、fields() 中,還能夠添加多個 mustBe() 方法
data class User(val name: String = "tony",val password: String = "abcdefg", val confirmPassword: String = "abcdefg" ,val email:String = "abc#abc.com") val propertyValidator = definePropertyValidator<User> { mustBe { name.isNotBlank() } field("password") { mustBe("password not blank") { password.isNotBlank() } mustBe("password length range") { password.length in 6..20 } } fields("password", "confirmPassword") { mustBe("password confirmPassword same") { password == confirmPassword } } field("email") { mustBe("verify email") { email.validate{ this addRule EmailRule() } }.errorMessage { "invalid email address" } } } fun main() { val user = User() val result = propertyValidator.validateAll(user) println(result) println(propertyValidator.validate(user)) } 複製代碼
在 email 字段中,mustBe() 裏使用了
email.validate{ this addRule EmailRule() } 複製代碼
它是一個擴展函數:
fun <T> T.validate(block: Validator<T>.() -> Unit): Boolean { val v = Validator<T>() block.invoke(v) return v.validate(this) } 複製代碼
它其實是調用了類的驗證,並添加了 EmailRule。
kvalidation 是一個基於 Kotlin 特性的驗證框架,這些特性包括範型、DSL、擴展函數、帶接收者的函數類型等等。所以,它使用起來簡潔,也有具備很好的可讀性。
Java與Android技術棧:每週更新推送原創技術文章,歡迎掃描下方的公衆號二維碼並關注,期待與您的共同成長和進步。