Delegasjonsmønster i Kotlin
1. Oversikt
Det er mange brukstilfeller der delegering foretrekkes fremfor arv. Kotlin har god språknivå støtte for dette.
I denne veiledningen, Vi snakker om Kotlins opprinnelige støtte til delegasjonsmønsteret og se det i aksjon.
2. Implementering
La oss først anta at vi har et kodeeksempel med strukturen nedenfor i et tredjepartsbibliotek:
grensesnitt Produsent {fun produce (): String} class ProducerImpl: Producer {override fun produce () = "ProducerImpl"}
Neste, la oss dekorere den eksisterende implementeringenved å bruke nøkkelordet og legg til den ekstra nødvendige behandlingen:
klasse EnhancedProducer (privat val delegat: produsent): produsent av delegat {override fun produce () = "$ {delegate.produce ()} og EnhancedProducer"}
Så i dette eksemplet har vi antydet at EnhancedProducer klasse vil kapsle inn a delegat objekt av typen Produsent. Og det kan også bruke funksjonalitet fra Produsent gjennomføring.
Til slutt, la oss kontrollere at det fungerer som forventet:
val producer = EnhancedProducer (ProducerImpl ()) assertThat (producer.produce ()). isEqualTo ("ProducerImpl and EnhancedProducer")
3. Bruk saker
La oss nå se på to vanlige brukssaker for delegeringsmønsteret.
Først kan vi bruke delegeringsmønsteret å implementere flere grensesnitt ved hjelp av eksisterende implementeringer:
klasse CompositeService: UserService av UserServiceImpl (), MessageService av MessageServiceImpl ()
For det andre kan vi bruke delegering for å forbedre en eksisterende implementering.
Det siste er hva vi gjorde i forrige avsnitt. Men et mer virkelig eksempel som det nedenfor er spesielt nyttig når vi ikke kan endre en eksisterende implementering - for eksempel tredjepartsbibliotekekode:
class SynchronizedProducer (private val delegate: Producer): Producer by delegate {private val lock = ReentrantLock () override fun produce (): String {lock.withLock {return delegate.produce ()}}}
4. Delegasjon er ikke arv
Nå må vi alltid huske det delegaten vet ingenting om dekoratøren. Så vi skal ikke prøve GoF-malmetode-liknende tilnærming med dem.
La oss vurdere et eksempel:
grensesnitt Service {val seed: Int fun serve (action: (Int) -> Unit)} class ServiceImpl: Service {override val seed = 1 override fun serve (action: (Int) -> Unit) {action (seed)}} class ServiceDecorator: Service by ServiceImpl () {override val seed = 2}
Her delegaten (ServiceImpl) bruker en egenskap definert i det felles grensesnittet, og vi overstyrer den i dekoratøren (ServiceDecorator). Imidlertid påvirker det ikke delegatens behandling:
val service = ServiceDecorator () service.serve {assertThat (it) .isEqualTo (1)}
Til slutt er det viktig å merke seg at i Kotlin, Vi kan delegere ikke bare til grensesnitt, men også til å skille egenskaper.
5. Konklusjon
I denne opplæringen snakket vi om Kotlin-grensesnittdelegering - når den skal brukes, hvordan du konfigurerer den og dens forbehold.
Som vanlig er den komplette kildekoden for denne artikkelen tilgjengelig på GitHub.