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

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

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

  1. sealed class กับ sealed interface: ควรใช้แบบใด
  2. when แบบครอบคลุมทุกกรณีกับลำดับชั้น Sealed
  3. จำลองสถานะ UI ด้วย Sealed Class
  4. การซ้อนและรวมลำดับชั้น Sealed
← กลับไปที่ Kotlin Academy