kotlinintermediate
Sealed Hierarchies for Domain Modeling
Use sealed interfaces and classes for exhaustive domain modeling with when expressions.
kotlinPress ⌘/Ctrl + Shift + C to copy
// Sealed interface allows multi-level hierarchies
sealed interface PaymentMethod {
data class CreditCard(
val number: String,
val expiry: String,
val cvv: String
) : PaymentMethod
data class BankTransfer(
val accountNumber: String,
val routingNumber: String
) : PaymentMethod
sealed interface DigitalWallet : PaymentMethod {
data class PayPal(val email: String) : DigitalWallet
data class ApplePay(val deviceToken: String) : DigitalWallet
data class GooglePay(val token: String) : DigitalWallet
}
data object Cash : PaymentMethod
}
// Processing with exhaustive when
fun processPayment(method: PaymentMethod, amount: Double): String = when (method) {
is PaymentMethod.CreditCard -> "Charging $$amount to card ending ${method.number.takeLast(4)}"
is PaymentMethod.BankTransfer -> "ACH transfer of $$amount"
is PaymentMethod.DigitalWallet.PayPal -> "PayPal charge to ${method.email}"
is PaymentMethod.DigitalWallet.ApplePay -> "Apple Pay: $$amount"
is PaymentMethod.DigitalWallet.GooglePay -> "Google Pay: $$amount"
PaymentMethod.Cash -> "Cash payment: $$amount"
}
fun fee(method: PaymentMethod): Double = when (method) {
is PaymentMethod.CreditCard -> 0.029
is PaymentMethod.BankTransfer -> 0.005
is PaymentMethod.DigitalWallet -> 0.015 // covers all digital wallets
PaymentMethod.Cash -> 0.0
}
// UI State modeling
sealed interface UiState<out T> {
data object Loading : UiState<Nothing>
data class Success<T>(val data: T) : UiState<T>
data class Error(val message: String, val retry: (() -> Unit)? = null) : UiState<Nothing>
data object Empty : UiState<Nothing>
}
fun <T> UiState<T>.render(): String = when (this) {
is UiState.Loading -> "Loading..."
is UiState.Success -> "Data: $data"
is UiState.Error -> "Error: $message"
is UiState.Empty -> "No data"
}
fun main() {
val payments = listOf(
PaymentMethod.CreditCard("4111111111111111", "12/25", "123"),
PaymentMethod.DigitalWallet.PayPal("user@test.com"),
PaymentMethod.BankTransfer("123456", "021000021"),
PaymentMethod.Cash
)
payments.forEach { method ->
println(processPayment(method, 99.99))
println(" Fee rate: ${fee(method) * 100}%")
}
// UI state
val states: List<UiState<String>> = listOf(
UiState.Loading,
UiState.Success("Hello"),
UiState.Error("Network error"),
UiState.Empty
)
states.forEach { println(it.render()) }
}Use Cases
- Payment processing with type-safe methods
- UI state management patterns
- Exhaustive domain event handling
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
kotlinbeginner
Enum Classes — Advanced Patterns
Use Kotlin enum classes with properties, methods, interfaces, and companion utilities.
Best for: Type-safe constant sets with behavior
#kotlin#enum
kotlinadvanced
Custom Property Delegates
Create reusable property delegates: validation, logging, caching, and thread-safe lazy initialization.
Best for: Input validation on property assignment
#kotlin#delegates
kotlinintermediate
Interface Delegation with 'by'
Delegate interface implementations with the 'by' keyword: composition over inheritance patterns.
Best for: Composition over inheritance
#kotlin#delegation
kotlinintermediate
Null Safety — Advanced Patterns
Master null safety in Kotlin: chaining, smart casts, safe builders, orElse patterns, and nullable collections.
Best for: Safe navigation through nested nullable objects
#kotlin#null-safety