สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด
สร้าง DSL สำหรับการกำหนดค่าอย่างง่ายด้วยรูปแบบ builder และ lambda ส่วนขยาย
สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
เป้าหมาย: DSL ที่ใช้งานได้จริง
เราจะสร้าง DSL ตัวสร้าง HTML ที่มีขนาดเล็กแต่สมจริงใน Kotlin รูปแบบเดียวกันนี้ใช้ได้กับตัวสร้างการกำหนดค่า ชุดข้อมูลสำหรับการทดสอบ หรือรายงาน ผลลัพธ์คือ API ที่ปลอดภัยตามชนิดข้อมูล รองรับสภาพแวดล้อมการพัฒนาได้ดี และใช้แทนการต่อสตริง
กำหนดคลาสพื้นฐานของ Tag
องค์ประกอบ HTML ทั้งหมดมีโครงสร้างร่วมกัน ได้แก่ ชื่อ แอตทริบิวต์ และองค์ประกอบลูก เริ่มต้นด้วยคลาสพื้นฐาน:
open class Tag(val name: String) {
val attrs = mutableMapOf<String, String>()
val children = mutableListOf<Tag>()
fun render(indent: Int = 0): String {
val pad = " ".repeat(indent)
val attrStr = if (attrs.isEmpty()) "" else " " + attrs.entries.joinToString(" ") { "${it.key}=\"${it.value}\"" }
val body = children.joinToString("\n") { it.render(indent + 2) }
return "$pad<$name$attrStr>\n$body\n$pad</$name>"
}
}ใช้ @DslMarker
กำหนดแอนโนเทชันให้คลาสตัวสร้างทั้งหมด เพื่อไม่ให้ขอบเขตภายในเรียกเมธอดจากขอบเขตภายนอกโดยไม่ตั้งใจ:
@DslMarker
annotation class HtmlDsl
@HtmlDsl class Html : Tag("html")
@HtmlDsl class Head : Tag("head")
@HtmlDsl class Body : Tag("body")
@HtmlDsl class Div : Tag("div")
@HtmlDsl class P : Tag("p")เพิ่มฟังก์ชันตัวสร้าง
คลาสแท็กแต่ละคลาสจะได้รับฟังก์ชันส่วนขยายที่สร้างแท็กลูก ใช้บล็อก และเพิ่มแท็กลูกนั้นลงในองค์ประกอบลูก:
fun Html.head(block: Head.() -> Unit) = Head().also { it.block(); children += it }
fun Html.body(block: Body.() -> Unit) = Body().also { it.block(); children += it }
fun Body.div(block: Div.() -> Unit) = Div().also { it.block(); children += it }
fun Div.p(text: String) = P().also { it.attrs["text"] = text; children += it }ตัวสร้าง html ระดับบนสุด
จัดเตรียมจุดเริ่มต้นระดับบนสุดที่สร้างองค์ประกอบรากและใช้บล็อกของผู้ใช้:
fun html(block: Html.() -> Unit): Html {
val root = Html()
root.block()
return root
}การใช้ DSL
ผลลัพธ์คือ DSL ที่สะอาดและอ่านง่าย:
val page = html {
head { }
body {
div {
p("Hello, DSL!")
}
}
}
println(page.render())การเพิ่มแอตทริบิวต์
เพิ่มตัวช่วย attr เพื่อตั้งค่าแอตทริบิวต์ตามอำเภอใจได้อย่างต่อเนื่อง:
fun Tag.attr(key: String, value: String) { attrs[key] = value }
// Usage
div {
attr("class", "container")
p("Content")
}รูปแบบ DSL สำหรับการกำหนดค่า
รูปแบบเดียวกันนี้ใช้ได้กับออบเจ็กต์การกำหนดค่า แทนที่จะใช้แท็ก HTML ให้ใช้คลาสเฉพาะโดเมน:
class ServerConfig {
var host = "localhost"
var port = 8080
var db: DbConfig? = null
fun database(block: DbConfig.() -> Unit) { db = DbConfig().apply(block) }
}
fun server(block: ServerConfig.() -> Unit) = ServerConfig().apply(block)การซ้อนและการประกอบ
เนื่องจากฟังก์ชันตัวสร้างแต่ละฟังก์ชันคืนค่าออบเจ็กต์ที่สร้างขึ้น คุณจึงสามารถประกอบตัวสร้างได้อย่างอิสระ ระดับความลึกของการซ้อน DSL จะตรงกับระดับความลึกของลำดับชั้นข้อมูล
การป้องกันข้อผิดพลาดด้วยชนิดข้อมูล
ระบบชนิดข้อมูลจะบังคับใช้โครงสร้าง คุณไม่สามารถเรียกใช้ body { } ภายใน Head ได้ เพราะ Head ไม่มีฟังก์ชันส่วนขยาย body โครงสร้างที่ไม่ถูกต้องจะทำให้เกิดข้อผิดพลาดขณะคอมไพล์
การเรนเดอร์และการทดสอบ
เนื่องจาก DSL สร้างต้นไม้ออบเจ็กต์ Kotlin ธรรมดา การเรนเดอร์และการทดสอบจึงทำได้ง่าย เพียงเรียกใช้ render() แล้วตรวจสอบสตริงผลลัพธ์ หรือเดินสำรวจต้นไม้ออบเจ็กต์ในการทดสอบ
การขยาย DSL ในภายหลัง
การเพิ่มแท็กใหม่หรือตัวเลือกการกำหนดค่าใหม่ต้องใช้เพียงฟังก์ชันส่วนขยายใหม่บนคลาสตัวรับที่เหมาะสมเท่านั้น จุดเรียกใช้เดิมไม่ได้รับผลกระทบ ซึ่งแสดงหลักการเปิด/ปิดได้ในทางปฏิบัติ
ตรวจสอบอย่างรวดเร็ว
อะไรทำให้ DSL ของ Kotlin สำหรับ HTML/การกำหนดค่ามีความปลอดภัยด้านชนิดข้อมูล
สรุปทบทวน: การสร้าง DSL ที่ปลอดภัยด้านชนิดข้อมูล
ขั้นตอนสำคัญ:
- กำหนดคลาสตัวสร้างสำหรับแต่ละระดับของลำดับชั้น
- ใส่คำอธิบายประกอบด้วย
@DslMarkerเพื่อป้องกันการรั่วไหลของตัวรับ - เขียนฟังก์ชันส่วนขยายที่สร้าง กำหนดค่า และเพิ่มออบเจ็กต์ลูก
- เปิดเผยฟังก์ชันจุดเริ่มต้นระดับบนสุด
- การแสดงผลและการทดสอบทำงานกับออบเจ็กต์ Kotlin ทั่วไป
คำถามที่พบบ่อย
บทเรียน “สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด”
สร้าง DSL สำหรับการกำหนดค่าอย่างง่ายด้วยรูปแบบ builder และ lambda ส่วนขยาย คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- Lambda พร้อมตัวรับ: รากฐานของ DSL
- @DslMarker: ป้องกันการรั่วไหลของตัวรับ
- สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด
- ทดสอบและพัฒนา DSL โดยไม่ทำลายผู้ใช้