Delegatiepatroon in Kotlin

1. Overzicht

Er zijn veel use-cases waarin delegatie de voorkeur heeft boven overerving. Kotlin heeft hiervoor geweldige ondersteuning op taalniveau.

In deze tutorial we zullen het hebben over Kotlin's native ondersteuning voor het delegatiepatroon en zie het in actie.

2. Implementatie

Laten we eerst aannemen dat we een codevoorbeeld hebben met de onderstaande structuur in een bibliotheek van derden:

interface Producer {fun produce (): String} class ProducerImpl: Producer {overschrijft fun produce () = "ProducerImpl"}

De volgende, laten we de bestaande implementatie versierenmet behulp van het trefwoord "op" en voeg de aanvullende noodzakelijke verwerking toe:

class EnhancedProducer (private val delegate: Producer): Producer per delegate {override fun produce () = "$ {delegate.produce ()} en EnhancedProducer"}

Dus in dit voorbeeld hebben we aangegeven dat de Verbeterde Producent klasse zal een delegeren object van het type Producent. En het kan ook functionaliteit gebruiken van de Producent implementatie.

Laten we tot slot controleren of het werkt zoals verwacht:

val producer = EnhancedProducer (ProducerImpl ()) assertThat (producer.produce ()). isEqualTo ("ProducerImpl en EnhancedProducer")

3. Gebruik gevallen

Laten we nu eens kijken naar twee veelvoorkomende gebruiksscenario's voor het delegatiepatroon.

Ten eerste kunnen we het delegatiepatroon gebruiken om meerdere interfaces te implementeren met behulp van bestaande implementaties:

klasse CompositeService: UserService door UserServiceImpl (), MessageService door MessageServiceImpl ()

Ten tweede kunnen we delegatie gebruiken om een ​​bestaande implementatie te verbeteren.

Dit laatste is wat we in de vorige sectie hebben gedaan. Maar een realistischer voorbeeld zoals het onderstaande is vooral handig als we een bestaande implementatie niet kunnen wijzigen, bijvoorbeeld bibliotheekcode van derden:

class SynchronizedProducer (private val delegate: Producer): Producer per delegate {private val lock = ReentrantLock () override fun produce (): String {lock.withLock {return delegate.produce ()}}}

4. Delegatie is geen erfenis

Nu moeten we dat altijd onthouden de afgevaardigde weet niets van de decorateur. Dus we moeten de GoF-sjabloonmethode-achtige benadering met hen.

Laten we een voorbeeld bekijken:

interface 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 door ServiceImpl () {overschrijven val seed = 2}

Hier, de afgevaardigde (ServiceImpl) gebruikt een eigenschap die is gedefinieerd in de gemeenschappelijke interface en we overschrijven deze in de decorateur (ServiceDecorator). Het heeft echter geen invloed op de verwerking van de gedelegeerde:

val service = ServiceDecorator () service.serve {assertThat (it) .isEqualTo (1)}

Ten slotte is het belangrijk op te merken dat in Kotlin we kunnen niet alleen delegeren aan interfaces, maar ook aan afzonderlijke eigenschappen.

5. Conclusie

In deze tutorial hebben we het gehad over Kotlin-interfacedelegatie - wanneer het moet worden gebruikt, hoe het moet worden geconfigureerd en de kanttekeningen.

Zoals gewoonlijk is de volledige broncode voor dit artikel beschikbaar op GitHub.