การซ้อนและรวมลำดับชั้น Sealed
สร้างเครื่องจักรสถานะที่ซับซ้อนด้วยการซ้อนชนิด sealed
การซ้อนและรวมลำดับชั้น Sealed เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
การประกอบต้นไม้สถานะ
สถานะในโลกจริงมักมีหลายมิติ ให้ซ้อนชนิดแบบปิดผนึกหรือรวมลำดับชั้นที่แยกกัน เพื่อจำลองโดเมนที่ซับซ้อนได้อย่างเป็นระเบียบ
คลาสแบบปิดผนึกซ้อนกัน
ประกาศชนิดแบบปิดผนึกลูกไว้ภายในชนิดแบบปิดผนึกภายนอก คอมไพเลอร์ยังคงบังคับให้ครอบคลุมครบถ้วนตลอดทั้งต้นไม้
sealed class UiState {
object Loading : UiState()
sealed class Loaded : UiState() {
data class Success(val items: List<String>) : Loaded()
data class Empty(val message: String) : Loaded()
}
data class Error(val msg: String) : UiState()
}
fun render(s: UiState) = when (s) {
UiState.Loading -> "loading"
is UiState.Loaded.Success -> "${s.items.size} items"
is UiState.Loaded.Empty -> "empty: ${s.message}"
is UiState.Error -> "err: ${s.msg}"
}
fun main() {
println(render(UiState.Loaded.Success(listOf("a", "b"))))
}อินเทอร์เฟซแบบปิดผนึกสำหรับส่วนผสม
ใช้อินเทอร์เฟซแบบปิดผนึกเมื่อสถานะมีองค์ประกอบหลายด้านที่ไม่ขึ้นต่อกัน โดยให้แต่ละด้านเป็นอินเทอร์เฟซคนละรายการ
sealed interface Authenticated
data class User(val id: Int) : Authenticated
object Guest
sealed interface Permission
object Read : Permission
object Write : Permission
fun describe(a: Authenticated, p: Permission): String = when {
a is User && p is Write -> "user ${a.id} can write"
a is User -> "user ${a.id} can read"
else -> "?"
}
fun main() {
println(describe(User(1), Write))
}การรวมลำดับชั้น
ส่งค่าชนิดแบบปิดผนึกสองค่า แล้วเลือกตามการรวมกันของทั้งสองค่า โดยใช้ when ที่มีเงื่อนไขกำกับ
sealed class Theme { object Light : Theme(); object Dark : Theme() }
sealed class Lang { object En : Lang(); object Tr : Lang() }
fun greet(theme: Theme, lang: Lang) = when {
theme is Theme.Dark && lang is Lang.Tr -> "Karanlik Merhaba"
theme is Theme.Light && lang is Lang.Tr -> "Aydinlik Merhaba"
theme is Theme.Dark -> "Dark Hello"
theme is Theme.Light -> "Light Hello"
else -> "?"
}
fun main() {
println(greet(Theme.Dark, Lang.Tr))
}เครื่องจักรสถานะที่มีรูปแบบซ้อนกัน
จำลองกระบวนการทำงานหลายขั้นตอนเป็นชนิดแบบปิดผนึกซ้อนกัน โดยแต่ละขั้นตอนมีรูปแบบของตนเอง
sealed class Checkout {
object Start : Checkout()
sealed class Payment : Checkout() {
object Pending : Payment()
data class Failed(val reason: String) : Payment()
object Captured : Payment()
}
object Shipped : Checkout()
object Delivered : Checkout()
}
fun describe(c: Checkout) = when (c) {
Checkout.Start -> "starting"
Checkout.Payment.Pending -> "awaiting payment"
is Checkout.Payment.Failed -> "payment failed: ${c.reason}"
Checkout.Payment.Captured -> "paid"
Checkout.Shipped -> "shipped"
Checkout.Delivered -> "delivered"
}
fun main() {
println(describe(Checkout.Payment.Failed("card declined")))
}การนำลำดับชั้นแบบปิดผนึกกลับมาใช้ข้ามโมดูล
ชนิดแบบปิดผนึกเหมาะที่สุดเมื่อกำหนดแยกภายในแต่ละโมดูล สำหรับการประกอบข้ามโมดูล ให้เปิดเผยอินเทอร์เฟซแบบปิดผนึกเพื่อให้แต่ละโมดูลเพิ่มการนำไปใช้ของตนเองได้
sealed interface Notification
data class Email(val to: String) : Notification
data class Sms(val phone: String) : Notification
fun send(n: Notification) = when (n) {
is Email -> "sending email to ${n.to}"
is Sms -> "texting ${n.phone}"
}
fun main() {
println(send(Email("a@example.com")))
}คุณสมบัติพื้นฐานร่วม
คลาสแบบปิดผนึกสามารถประกาศคุณสมบัติร่วมกันได้ ชนิดย่อยทั้งหมดจะสืบทอดคุณสมบัติเหล่านั้น ช่วยให้สถานะและข้อมูลกำกับเป็นไปตามหลัก DRY
sealed class HttpResponse(val code: Int) {
class Ok(val body: String) : HttpResponse(200)
class NotFound(val path: String) : HttpResponse(404)
class ServerError(val cause: String) : HttpResponse(500)
}
fun describe(r: HttpResponse) = "[${r.code}] " + when (r) {
is HttpResponse.Ok -> r.body
is HttpResponse.NotFound -> "not found: ${r.path}"
is HttpResponse.ServerError -> "fail: ${r.cause}"
}
fun main() {
println(describe(HttpResponse.Ok("hello")))
}การจำลองต้นไม้แบบเวียนเกิด
ชนิดแบบปิดผนึกสามารถอธิบายโครงสร้างแบบเวียนเกิด เช่น ต้นไม้นิพจน์ ได้อย่างเป็นธรรมชาติ
sealed class Expr {
data class Num(val value: Int) : Expr()
data class Add(val left: Expr, val right: Expr) : Expr()
data class Mul(val left: Expr, val right: Expr) : Expr()
}
fun eval(e: Expr): Int = when (e) {
is Expr.Num -> e.value
is Expr.Add -> eval(e.left) + eval(e.right)
is Expr.Mul -> eval(e.left) * eval(e.right)
}
fun main() {
val expr = Expr.Add(Expr.Num(3), Expr.Mul(Expr.Num(4), Expr.Num(5)))
println(eval(expr)) // 23
}การใช้ร่วมกับชนิดทั่วไป
ชนิดแบบปิดผนึกสามารถเป็นชนิดทั่วไปได้ ทำให้สร้างซองผลลัพธ์ที่มีชนิดกำกับ เช่น Result<T> ได้
sealed class ApiResult<out T> {
data class Success<T>(val data: T) : ApiResult<T>()
data class Failure(val message: String) : ApiResult<Nothing>()
}
fun handle(r: ApiResult<String>) = when (r) {
is ApiResult.Success -> "got ${r.data}"
is ApiResult.Failure -> "err: ${r.message}"
}
fun main() {
println(handle(ApiResult.Success("hi")))
println(handle(ApiResult.Failure("nope")))
}รูปแบบที่ไม่ควรใช้: การซ้อนลึกเกินไป
การซ้อนลึกจะบดบังเจตนา หากต้นไม้แบบปิดผนึกมีความลึกเกิน 2 ระดับ โปรดพิจารณาทำให้แบนราบหรือนำต้นไม้ย่อยไปไว้ในไฟล์ของตนเอง
sealed class Top {
sealed class Mid : Top() {
sealed class Deep : Mid() {
object Leaf : Deep()
}
}
}
fun main() {
val l = Top.Mid.Deep.Leaf
println(l::class.simpleName)
}การรวมด้วยการประกอบ
เมื่อมิติสถานะสองด้านเป็นอิสระต่อกัน ควรใช้การประกอบ (คลาสข้อมูลที่ห่อค่าชนิดแบบปิดผนึกสองค่า) แทนลำดับชั้นที่ซ้อนลึก
sealed class Loading { object Active : Loading(); object Idle : Loading() }
sealed class Auth { data class Signed(val id: Int) : Auth(); object Anon : Auth() }
data class AppState(val loading: Loading, val auth: Auth)
fun main() {
val s = AppState(Loading.Active, Auth.Signed(1))
println(s)
}ตรวจสอบอย่างรวดเร็ว
เมื่อมิติสถานะสองด้านเป็นอิสระต่อกัน ควรใช้แนวทางใด
ทบทวน
ซ้อนชนิดแบบปิดผนึกสำหรับสถานะรูปต้นไม้ และรวมลำดับชั้นแบบปิดผนึกที่เป็นอิสระต่อกันด้วยการประกอบ (คลาสข้อมูลที่ใช้ห่อหุ้ม) เพิ่มคุณสมบัติร่วมให้ฐานแบบปิดผนึก ใช้ชนิดทั่วไปสำหรับผลลัพธ์ที่มีชนิดกำกับ และจำลองโครงสร้างแบบเวียนเกิดอย่างเป็นธรรมชาติ ควรรักษาความลึกของการซ้อนให้ตื้น
คำถามที่พบบ่อย
บทเรียน “การซ้อนและรวมลำดับชั้น Sealed” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การซ้อนและรวมลำดับชั้น Sealed” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การซ้อนและรวมลำดับชั้น Sealed”
สร้างเครื่องจักรสถานะที่ซับซ้อนด้วยการซ้อนชนิด sealed คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การซ้อนและรวมลำดับชั้น Sealed” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- sealed class กับ sealed interface: ควรใช้แบบใด
- when แบบครอบคลุมทุกกรณีกับลำดับชั้น Sealed
- จำลองสถานะ UI ด้วย Sealed Class
- การซ้อนและรวมลำดับชั้น Sealed