0Pricing
Kotlin Academy · บทเรียน

การตรวจสอบและการจับคู่ด้วย 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. Reflection ของ Kotlin: KClass, KFunction, KProperty
  2. การสร้างและกำหนดเป้าหมายคำอธิบายประกอบแบบกำหนดเอง
  3. การอ่านคำอธิบายประกอบขณะรันไทม์
  4. การตรวจสอบและการจับคู่ด้วย Reflection
← กลับไปที่ Kotlin Academy