Sealed-hierarkioiden sisäkkäisyys ja yhdistäminen
Rakentakaa monimutkaisia tilakoneita sisäkkäisten sealed-tyyppien avulla.
Sealed-hierarkioiden sisäkkäisyys ja yhdistäminen on ilmainen Kotlin Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Kotlin Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Kotlin Academy-kurssilla on yhteensä 4 oppituntia.
Tilapuiden koostaminen
Tosielämän tiloilla on usein useita ulottuvuuksia. Sisäkkäiset sealed-tyypit tai erillisten hierarkioiden yhdistäminen auttavat mallintamaan monimutkaiset toimialueet selkeästi.
Sisäkkäinen sealed-luokka
Määritelkää alisteiset sealed-tyypit ulomman sealed-tyypin sisälle. Kääntäjä valvoo edelleen täydellisyyttä koko puun alueella.
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-rajapinnat mixineille
Käyttäkää sealed-rajapintoja, kun tilalla on useita toisistaan riippumattomia ominaisuuksia – kukin ominaisuus toteutetaan eri rajapintana.
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))
}Hierarkioiden yhdistäminen
Välittäkää kaksi sealed-arvoa ja käsitelkää niiden yhdistelmää – käyttäkää ehtoja sisältävää when-lauseketta.
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))
}Tilakone sisäkkäisillä muunnoksilla
Mallintakaa monivaiheiset työnkulut sisäkkäisinä sealed-tyyppeinä – kullakin vaiheella on omat muunnoksensa.
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-hierarkioiden uudelleenkäyttö moduulien välillä
Sealed-tyypit kannattaa määritellä moduulikohtaisesti. Moduulien välisessä koostamisessa paljastakaa sealed interface, jotta kukin moduuli voi lisätä omat toteutuksensa.
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")))
}Yhteiset kantaluokan ominaisuudet
Sealed-luokat voivat määritellä yhteisiä ominaisuuksia, jotka kaikki alityypit perivät. Näin tila ja metatiedot pysyvät DRY-periaatteen mukaisina.
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")))
}Rekursiivisten puiden mallintaminen
Sealed-tyypit kuvaavat luontevasti rekursiivisia rakenteita, kuten lausekepuita.
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
}Geneeristen tyyppien yhdistäminen
Sealed-tyypit voivat olla geneerisiä, mikä mahdollistaa tyypitetyt tuloskuoret, kuten 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")))
}Vastaesimerkki: liian syvä sisäkkäisyys
Syvä sisäkkäisyys peittää tarkoituksen. Jos sealed-puussa on yli kaksi tasoa, harkitkaa sen litistämistä tai alipuujen erottamista omiin tiedostoihinsa.
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)
}Yhdistäminen koostamalla
Kun kaksi tilaulottuvuutta ovat toisistaan riippumattomia, suosikaa koostamista (data class, joka sisältää kaksi sealed-arvoa) syvästi sisäkkäisten hierarkioiden sijaan.
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)
}Pikatarkistus
Mitä suositellaan, kun kaksi tilaulottuvuutta ovat toisistaan riippumattomia?
Kertaus
Sisäkkäistäkää sealed-tyyppejä puumaista tilaa varten ja yhdistäkää toisistaan riippumattomat sealed-hierarkiat koostamalla (käärivällä data classilla). Lisätkää yhteiset ominaisuudet sealed-kantaluokkaan, käyttäkää geneerisiä tyyppejä tyypitettyihin tuloksiin ja mallintakaa rekursiiviset rakenteet luontevasti. Pitäkää sisäkkäisyys matalana.
Opi Kotlin tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 51
- Oppitunnit
- 203
Usein kysytyt kysymykset
Onko oppitunti ”Sealed-hierarkioiden sisäkkäisyys ja yhdistäminen” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Kotlin Academy-oppimispolun 3 oppituntia, myös oppitunnin “Sealed-hierarkioiden sisäkkäisyys ja yhdistäminen”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Kotlin Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Sealed-hierarkioiden sisäkkäisyys ja yhdistäminen”?
Rakentakaa monimutkaisia tilakoneita sisäkkäisten sealed-tyyppien avulla. Harjoittelet Kotlin Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Kotlin Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Kotlin Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.
Kuinka kauan ”Sealed-hierarkioiden sisäkkäisyys ja yhdistäminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Kotlin Academy-oppitunnilla?
Kyllä. Jokainen Kotlin Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- sealed class ja sealed interface: milloin kumpaakin käytetään
- Kattava when sealed-hierarkioilla
- Käyttöliittymän tilan mallintaminen sealed-luokilla
- Sealed-hierarkioiden sisäkkäisyys ja yhdistäminen