kotlinintermediate
Sealed Interfaces — Flexible Hierarchies
Use sealed interfaces for multi-hierarchy modeling: states, results, commands, and event systems.
kotlinPress ⌘/Ctrl + Shift + C to copy
// Sealed interface allows multiple inheritance
sealed interface UIEvent
sealed interface Loggable {
val logMessage: String
}
// Events can implement multiple sealed interfaces
data class Click(val x: Int, val y: Int) : UIEvent, Loggable {
override val logMessage = "Click at ($x, $y)"
}
data class KeyPress(val key: Char) : UIEvent, Loggable {
override val logMessage = "Key pressed: $key"
}
data class Scroll(val delta: Int) : UIEvent {
// Not Loggable
}
// State machine with sealed interface
sealed interface ConnectionState {
data object Disconnected : ConnectionState
data object Connecting : ConnectionState
data class Connected(val sessionId: String) : ConnectionState
data class Error(val reason: String) : ConnectionState
data class Reconnecting(val attempt: Int, val maxAttempts: Int) : ConnectionState
}
class ConnectionManager {
var state: ConnectionState = ConnectionState.Disconnected
private set
fun connect() {
state = when (state) {
is ConnectionState.Disconnected,
is ConnectionState.Error -> {
println("Connecting...")
ConnectionState.Connecting
}
else -> {
println("Already connecting/connected")
state
}
}
}
fun onConnected(sessionId: String) {
state = ConnectionState.Connected(sessionId)
println("Connected: $sessionId")
}
fun onError(reason: String) {
state = ConnectionState.Error(reason)
println("Error: $reason")
}
fun statusMessage(): String = when (val s = state) {
ConnectionState.Disconnected -> "Not connected"
ConnectionState.Connecting -> "Connecting..."
is ConnectionState.Connected -> "Connected (${s.sessionId})"
is ConnectionState.Error -> "Error: ${s.reason}"
is ConnectionState.Reconnecting -> "Reconnecting (${s.attempt}/${s.maxAttempts})"
}
}
// Command pattern with sealed interface
sealed interface Command {
data class CreateUser(val name: String, val email: String) : Command
data class UpdateUser(val id: String, val name: String) : Command
data class DeleteUser(val id: String) : Command
data class SendEmail(val to: String, val subject: String, val body: String) : Command
}
sealed interface CommandResult {
data class Success(val message: String) : CommandResult
data class Failure(val error: String) : CommandResult
}
fun executeCommand(cmd: Command): CommandResult = when (cmd) {
is Command.CreateUser -> CommandResult.Success("Created user: ${cmd.name}")
is Command.UpdateUser -> CommandResult.Success("Updated user: ${cmd.id}")
is Command.DeleteUser -> CommandResult.Success("Deleted user: ${cmd.id}")
is Command.SendEmail -> CommandResult.Success("Sent email to: ${cmd.to}")
}
// Sealed interface for JSON values
sealed interface JsonValue {
data class JsonString(val value: String) : JsonValue
data class JsonNumber(val value: Double) : JsonValue
data class JsonBool(val value: Boolean) : JsonValue
data class JsonArray(val items: List<JsonValue>) : JsonValue
data class JsonObject(val fields: Map<String, JsonValue>) : JsonValue
data object JsonNull : JsonValue
fun stringify(): String = when (this) {
is JsonString -> "\"$value\""
is JsonNumber -> if (value == value.toLong().toDouble()) value.toLong().toString() else value.toString()
is JsonBool -> value.toString()
is JsonArray -> items.joinToString(", ", "[", "]") { it.stringify() }
is JsonObject -> fields.entries.joinToString(", ", "{", "}") {
"\"${it.key}\": ${it.value.stringify()}"
}
JsonNull -> "null"
}
}
fun main() {
// Events
val events: List<UIEvent> = listOf(
Click(100, 200),
KeyPress('A'),
Scroll(-3)
)
events.forEach { event ->
print("Event: ${event::class.simpleName}")
if (event is Loggable) print(" [${event.logMessage}]")
println()
}
// Connection state machine
println("\n--- Connection ---")
val conn = ConnectionManager()
println(conn.statusMessage())
conn.connect()
println(conn.statusMessage())
conn.onConnected("sess-123")
println(conn.statusMessage())
// Commands
println("\n--- Commands ---")
val commands = listOf(
Command.CreateUser("Alice", "alice@test.com"),
Command.SendEmail("bob@test.com", "Hello", "World")
)
commands.forEach { cmd ->
val result = executeCommand(cmd)
println("$result")
}
// JSON values
println("\n--- JSON ---")
val json = JsonValue.JsonObject(mapOf(
"name" to JsonValue.JsonString("Alice"),
"age" to JsonValue.JsonNumber(30.0),
"active" to JsonValue.JsonBool(true),
"tags" to JsonValue.JsonArray(listOf(
JsonValue.JsonString("kotlin"),
JsonValue.JsonString("dev")
)),
"address" to JsonValue.JsonNull
))
println(json.stringify())
}Use Cases
- Multi-interface state modeling
- Command and event pattern implementation
- Type-safe AST and data representation
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
kotlinintermediate
Interface Delegation with 'by'
Delegate interface implementations with the 'by' keyword: composition over inheritance patterns.
Best for: Composition over inheritance
#kotlin#delegation
kotlinintermediate
Sealed Hierarchies for Domain Modeling
Use sealed interfaces and classes for exhaustive domain modeling with when expressions.
Best for: Payment processing with type-safe methods
#kotlin#sealed
kotlinbeginner
Null Safety — Elvis, Safe Call, and let
Master Kotlin null safety: safe calls, Elvis operator, let/also scoping, and smart casts.
Best for: Safe navigation through nullable chains
#kotlin#null-safety
kotlinbeginner
Data Classes — Copy, Destructure, and Equals
Use data classes for immutable models: auto-generated equals, hashCode, copy, and destructuring.
Best for: Immutable domain models and DTOs
#kotlin#data-class