Middle
Welche Entwurfsmuster können in der Kotlin-Sprache verwendet werden?
sobes.tech KI
Antwort von AI
In Kotlin werden häufig folgende Muster angewendet:
- Singleton: Wird einfach durch
objectrealisiert.object MeinSingleton { fun machEtwas() { // ... } } - Factory Method: Verwendet eine abstrakte Funktion in der Superklasse oder Schnittstelle, die von Unterklassen zur Objekterstellung implementiert wird.
interface Produkt { fun operation() } class KonkretesProduktA : Produkt { override fun operation() { // ... } } abstract class Erzeuger { abstract fun FabrikMethode(): Produkt fun someOperation(): Produkt { val produkt = FabrikMethode() // ... return produkt } } class KonkreterErzeugerA : Erzeuger() { override fun FabrikMethode(): Produkt { return KonkretesProduktA() } } - Abstract Factory: Gruppe von Fabriken zur Erstellung verwandter Objektfamilien.
interface AbstraktesProduktA { fun nützlicheFunktionA() } interface AbstraktesProduktB { fun nützlicheFunktionB() fun eineWeitereNützlicheFunktionB(Kollaborateur: AbstraktesProduktA) } interface AbstrakteFabrik { fun createProduktA(): AbstraktesProduktA fun createProduktB(): AbstraktesProduktB } // Konkrete Implementierungen von Produkten und Fabriken... - Builder: Vereinfacht die schrittweise Erstellung komplexer Objekte.
class Pizza private constructor( val kruste: String, val soße: String?, val toppings: List<String> ) { data class Builder( var kruste: String = "dünn", var soße: String? = null, val toppings: MutableList<String> = mutableListOf() ) { fun mitKruste(kruste: String) = apply { this.kruste = kruste } fun mitSoße(soße: String) = apply { this.soße = soße } fun fügeToppingHinzu(topping: String) = apply { this.toppings.add(topping) } fun build() = Pizza(kruste, soße, toppings) } } fun main() { val pizza = Pizza.Builder() .mitKruste("dick") .mitSoße("Tomate") .fügeToppingHinzu("Pepperoni") .fügeToppingHinzu("Pilze") .build() // ... Pizza verwenden } - Adapter: Ermöglicht die Zusammenarbeit von Objekten mit inkompatiblen Schnittstellen.
open class Adaptee { fun spezifischeOperation() { // ... } } interface Target { fun operation() } class Adapter(private val adaptee: Adaptee) : Target { override fun operation() { adaptee.spezifischeOperation() } } - Decorator: Fügt bestehenden Objekten neue Funktionen hinzu, ohne ihre Struktur zu verändern. Erweiterungen und Delegierung in Kotlin erleichtern dies erheblich.
interface DataSource { fun readData(): String fun writeData(data: String) } class FileDataSource(private val dateiName: String) : DataSource { override fun readData(): String { // Aus Datei lesen return "" } override fun writeData(data: String) { // In Datei schreiben } } class EncryptionDecorator(private val source: DataSource) : DataSource by source { override fun readData(): String { // Daten entschlüsseln val data = source.readData() return data // entschlüsselte Daten } override fun writeData(data: String) { // Daten verschlüsseln source.writeData(data) // verschlüsselte Daten } } - Observer: Definiert die "1 zu vielen"-Abhängigkeit. Coroutines Flow und delegated properties in Kotlin können für die Implementierung genutzt werden.
// Einfache Implementierung ohne Flow interface Observer { fun update(message: String) } class Subject { private val observers = mutableListOf<Observer>() fun attach(observer: Observer) { observers.add(observer) } fun detach(observer: Observer) { observers.remove(observer) } fun notifyObservers(message: String) { observers.forEach { it.update(message) } } } - Strategy: Definiert eine Familie von Algorithmen, kapselt jeden und macht sie austauschbar.
interface PaymentStrategy { fun pay(amount: Double) } class PayByCreditCard(private val cardNumber: String) : PaymentStrategy { override fun pay(amount: Double) { println("Zahle $amount mit Kreditkarte $cardNumber") } } class PayByPayPal(private val email: String) : PaymentStrategy { override fun pay(amount: Double) { println("Zahle $amount mit PayPal $email") } } class Order(private val paymentStrategy: PaymentStrategy) { fun processOrder(amount: Double) { // ... Bestellverarbeitung paymentStrategy.pay(amount) } } - State: Ermöglicht einem Objekt, sein Verhalten je nach internem Zustand zu ändern. Sealed classes und when-Ausdrücke vereinfachen die Implementierung.
sealed class State { object Idle : State() object Loading : State() data class Error(val message: String) : State() data class Success(val data: Any) : State() } class Context { var state: State = State.Idle fun handleEvent() { when (state) { State.Idle -> { println("Ereignis im Idle-Zustand") state = State.Loading } State.Loading -> { println("Ereignis im Lade-Zustand, ignorieren") } is State.Error -> { println("Ereignis im Fehler-Zustand: ${state.message}") // Möglicher Übergang in einen anderen Zustand } is State.Success -> { println("Ereignis im Erfolg-Zustand: ${state.data}") // Möglicher Übergang in einen anderen Zustand } } } }