การตรวจสอบและการจับคู่ด้วย Reflection
สร้างตัวตรวจสอบหรือตัวแปลงออบเจ็กต์อย่างง่ายด้วย reflection ที่ขับเคลื่อนด้วยคำอธิบายประกอบ
การตรวจสอบและการจับคู่ด้วย Reflection เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
รูปแบบนี้แก้ปัญหาอะไร
การตรวจสอบความถูกต้องโดยใช้รีเฟล็กชันจะอ่านคำอธิบายประกอบจากคุณสมบัติของคลาสในขณะทำงาน แล้วใช้กฎการตรวจสอบโดยอัตโนมัติ จึงไม่ต้องตรวจสอบแต่ละฟิลด์ด้วยตนเอง เทคนิคเดียวกันนี้ใช้ขับเคลื่อนตัวแมปออบเจ็กต์กับฐานข้อมูลที่แปลงระหว่างออบเจ็กต์กับแถวในฐานข้อมูล
แอนโนเทชัน Validate
กำหนดแอนโนเทชันที่คงอยู่ขณะรันไทม์และมีพร็อพเพอร์ตีเป็นเป้าหมาย:
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class Validate(
val minLength: Int = 0,
val maxLength: Int = Int.MAX_VALUE,
val pattern: String = ""
)การใส่แอนโนเทชันให้คลาสข้อมูล
ใส่ @Validate ให้พร็อพเพอร์ตีของคลาสข้อมูล ตัวตรวจสอบจะสแกนพร็อพเพอร์ตีเหล่านี้ขณะรันไทม์:
data class UserForm(
@Validate(minLength = 2, maxLength = 50) val name: String,
@Validate(pattern = "^[\\w.]+@[\\w]+\\.[a-z]{2,}$") val email: String,
@Validate(minLength = 8) val password: String
)ฟังก์ชันตัวตรวจสอบ
ใช้ KClass.declaredMemberProperties เพื่อวนผ่านพร็อพเพอร์ตี ค้นหาแอนโนเทชัน และรวบรวมข้อผิดพลาด:
fun validate(obj: Any): List<String> {
val errors = mutableListOf<String>()
for (prop in obj::class.declaredMemberProperties) {
val ann = prop.findAnnotation<Validate>() ?: continue
val value = (prop as KProperty1<Any, *>).get(obj)?.toString() ?: ""
if (value.length < ann.minLength) errors += "${prop.name}: too short"
if (value.length > ann.maxLength) errors += "${prop.name}: too long"
if (ann.pattern.isNotEmpty() && !value.matches(Regex(ann.pattern)))
errors += "${prop.name}: invalid format"
}
return errors
}การเรียกใช้ตัวตรวจสอบ
เรียกใช้ validate() กับออบเจ็กต์ใดก็ได้ที่มีแอนโนเทชัน ฟังก์ชันนี้จะส่งคืนรายการข้อความข้อผิดพลาด โดยรายการว่างหมายความว่าข้อมูลถูกต้อง:
val form = UserForm("A", "not-an-email", "short")
val errors = validate(form)
errors.forEach(::println)
// name: too short
// email: invalid format
// password: too shortการแปลงออบเจ็กต์เป็นแผนที่ด้วย @Column
รูปแบบรีเฟลกชันอีกแบบหนึ่งใช้แปลงออบเจ็กต์เป็น Map โดยใช้แอนโนเทชัน @Column เพื่อระบุชื่อคอลัมน์:
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class Column(val name: String)
fun toMap(obj: Any): Map<String, Any?> =
obj::class.declaredMemberProperties
.mapNotNull { prop ->
val col = prop.findAnnotation<Column>() ?: return@mapNotNull null
col.name to (prop as KProperty1<Any, *>).get(obj)
}.toMap()การใช้ตัวแปลง
ใส่แอนโนเทชันให้คลาสข้อมูล แล้วเรียกใช้ toMap() เพื่อรับแผนที่ที่ใช้คอลัมน์เป็นคีย์ ซึ่งพร้อมสำหรับคำสั่ง INSERT:
data class User(
@Column("user_name") val name: String,
@Column("user_email") val email: String
)
val user = User("Alice", "alice@example.com")
println(toMap(user))
// {user_name=Alice, user_email=alice@example.com}การแคชผลลัพธ์จากรีเฟลกชัน
การสแกนด้วยรีเฟลกชันใช้ทรัพยากรมาก ให้แคชการจับคู่พร็อพเพอร์ตีกับแอนโนเทชันตั้งแต่เริ่มต้น โดยใช้ ConcurrentHashMap ที่มีคีย์เป็น KClass:
val cache = ConcurrentHashMap<KClass<*>, List<Pair<KProperty1<Any,*>, Column>>>()
fun columnsOf(klass: KClass<*>) = cache.getOrPut(klass) {
klass.declaredMemberProperties
.mapNotNull { p ->
p.findAnnotation<Column>()?.let { (p as KProperty1<Any,*>) to it }
}
}การรวมการตรวจสอบและการแปลง
คุณสามารถใส่แอนโนเทชันหลายตัวให้พร็อพเพอร์ตีเดียว แล้วประมวลผลแต่ละตัวแยกกันได้ ขั้นแรกให้ตรวจสอบ แล้วจึงแปลง หรือจะทำทั้งสองอย่างในการวนรอบเดียวโดยรวบรวมแอนโนเทชันแต่ละชนิดก็ได้:
data class Product(
@Validate(minLength = 1) @Column("product_name") val name: String,
@Column("price") val price: Double
)ข้อจำกัด
การตรวจสอบด้วยรีเฟลกชันมีประสิทธิภาพสูง แต่ก็มีข้อแลกเปลี่ยน ได้แก่ เพิ่มภาระการทำงานขณะรันไทม์ ต้องอาศัยการคงอยู่ของแอนโนเทชัน และไม่สามารถตรวจพบข้อผิดพลาดขณะคอมไพล์ได้ หากต้องการการตรวจสอบที่เน้นประสิทธิภาพหรือปลอดภัยตั้งแต่เวลาคอมไพล์ ให้พิจารณาใช้โค้ดที่สร้างด้วย KSP แทน
ควรใช้รูปแบบนี้เมื่อใด
การตรวจสอบด้วยรีเฟลกชันเหมาะอย่างยิ่งกับโค้ดของเฟรมเวิร์กที่ต้องรองรับคลาสที่ผู้ใช้กำหนดเองได้หลากหลาย เช่น ระบบแมปฐานข้อมูลเชิงวัตถุ ตัวแปลงข้อมูล ตัวตรวจสอบแบบฟอร์ม และตัวผูกการกำหนดค่า ส่วนโค้ดระดับแอปพลิเคชันที่เป็นเจ้าของชนิดข้อมูลเองควรเลือกใช้การตรวจสอบแบบระบุชัดเจน เพื่อความเร็วและความเข้าใจง่าย
ตรวจสอบความเข้าใจ
นโยบายการคงอยู่ของแอนโนเทชันแบบใดที่จำเป็น เพื่อให้แอนโนเทชันสำหรับการตรวจสอบสามารถอ่านได้ขณะรันไทม์
สรุป: การตรวจสอบและการแปลงด้วยรีเฟลกชัน
ประเด็นสำคัญ:
- ประกาศแอนโนเทชันที่คงอยู่ขณะรันไทม์และมีพร็อพเพอร์ตีเป็นเป้าหมาย
- ใช้
declaredMemberPropertiesร่วมกับfindAnnotationเพื่อควบคุมการตรวจสอบหรือการแปลง - แคชผลลัพธ์แยกตาม
KClassเพื่อหลีกเลี่ยงภาระจากรีเฟลกชันที่เกิดซ้ำ - ใส่แอนโนเทชันหลายตัวให้พร็อพเพอร์ตีเดียวเพื่อให้ทำงานร่วมกัน
- พิจารณาใช้ KSP เป็นทางเลือกที่ทำงานขณะคอมไพล์ในส่วนที่เน้นประสิทธิภาพ
คำถามที่พบบ่อย
บทเรียน “การตรวจสอบและการจับคู่ด้วย Reflection” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การตรวจสอบและการจับคู่ด้วย Reflection” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การตรวจสอบและการจับคู่ด้วย Reflection”
สร้างตัวตรวจสอบหรือตัวแปลงออบเจ็กต์อย่างง่ายด้วย reflection ที่ขับเคลื่อนด้วยคำอธิบายประกอบ คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การตรวจสอบและการจับคู่ด้วย Reflection” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- Reflection ของ Kotlin: KClass, KFunction, KProperty
- การสร้างและกำหนดเป้าหมายคำอธิบายประกอบแบบกำหนดเอง
- การอ่านคำอธิบายประกอบขณะรันไทม์
- การตรวจสอบและการจับคู่ด้วย Reflection