ProgrammatieKotlin ontwikkelaar

Wat zijn sealed interfaces in Kotlin, hoe werken ze in de praktijk en hoe verschillen ze van sealed classes?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

Geschiedenis van de vraag

In de vroege versies van Kotlin werden sealed classes gebruikt om de typehiërarchie te beperken, waardoor ontwikkelaars de toegestane subtypes expliciet konden beheersen door alleen kindklassen binnen één bestand te declareren. Voor sommige taken was dit niet voldoende, vooral als het nodig was om soortgelijke hiërarchieën met interfaces te beschrijven. Om dit probleem op te lossen, werd met Kotlin 1.5 de sealed modifier voor interfaces geïntroduceerd.

Probleem

Gewone interfaces kunnen overal in het project worden geïmplementeerd, wat vaak het waarborgen van de absolute sluiting van de typehiërarchie en het gebruik van uitputtende typecontroles (exhaustive when) in de weg staat. Dit kan leiden tot runtime-fouten en het onvermogen om alle varianten statisch te controleren.

Oplossing

Sealed interfaces maken het mogelijk om de lijst van implementerende klassen binnen één bestand te beperken, waardoor de voorspelbaarheid van het type-systeem en de veiligheid van patroonmatching worden verhoogd.

sealed interface NetworkResult class Success(val data: String): NetworkResult class Failure(val error: Throwable): NetworkResult fun handle(result: NetworkResult) = when(result) { is Success -> println("Data: ${result.data}") is Failure -> println("Error: ${result.error}") // Alle varianten zijn overwogen, 'else' is niet nodig }

Belangrijke kenmerken:

  • Sealed interfaces staan een enkele hiërarchie toe: alleen klassen/objecten uit hetzelfde bestand kunnen ervan erven
  • Sealed interfaces kunnen zowel door klassen als door objecten worden geïmplementeerd
  • Verhogen de typeveiligheid van de when-uitdrukking zonder expliciet een else te hoeven overwegen

Vraag met een addertje onder het gras.

Kan een sealed interface in een apart bestand worden toegevoegd of buiten het oorspronkelijke bestand worden geïmplementeerd?

Nee. Alle types die direct een sealed interface implementeren, moeten in hetzelfde bestand zijn gedeclareerd; anders geeft de compiler een foutmelding.

Mag een sealed interface subinterfaces buiten het declaratiebestand hebben?

Nee. Subinterfaces moeten ook in hetzelfde bestand staan. De hele hiërarchie is binnen het bestand gesloten.

Beïnvloeden sealed interfaces de runtime-prestaties?

Niet direct, maar ze maken veilige typecontroles tijdens de compilatie mogelijk, wat de kans op runtime-fouten verkleint, de code vereenvoudigt en indirect de tests kan versnellen.

Typische fouten en anti-patronen

  • Declaratie van implementerende klassen van een sealed interface buiten het bestand waar de interface zelf is gedeclareerd
  • Het toevoegen van te veel varianten, wat onderhoud moeilijk maakt
  • Het gebruik van sealed interface wanneer de hiërarchie van varianten kan veranderen (sluiting van varianten is niet vereist)

Voorbeeld uit het leven

Negatieve case

Een ontwikkelaar declareert een sealed interface NetworkAction in één bestand, maar de implementaties zijn verspreid over verschillende klassen en bestanden. Het probleem wordt later ontdekt: de compiler geeft aan dat de regel is geschonden, en het is moeilijk om de structuur te corrigeren, vooral in een groot project.

Voordelen:

  • Maakt het mogelijk om nieuwe implementaties te declareren zonder één bestand te bewerken

Nadelen:

  • Schendt de garanties van typeveiligheid
  • Dwingt tot refactoring van de code, wat tijdrovend is

Positieve case

De sealed interface OrderResult en de klassen Success/Failure worden binnen één bestand gedeclareerd. De when-controle is altijd uitputtend, geen enkele tak is overgeslagen.

Voordelen:

  • Veiligheid en volledigheid van behandelingen
  • Verbetert de kwaliteit van de architectuur

Nadelen:

  • Minder flexibele uitbreidbaarheid (alle wijzigingen alleen via dit bestand)