Czas na małe podsumowanie delegatów. Wiemy, że Kotlin ma mechanizm, który pozwala na generowanie wzorca delegata dla funkcji oraz wiemy co dzieje się w przypadku konfliktów nazw. Wiemy też, że Kotlin posiada mechanizm pozwalający na delegowanie właściwości w celu np. leniwego wartościowania oraz pozwala na budowę obiektów za pomocą map.

Dziś przyjrzymy się jakie delegaty dla własności oferuje nam biblioteka standardowa Kotlina.

Lazy

Jeżeli jesteśmy leniwi to, zamiast własnej leniwej inicjacji możemy skorzystać z gotowego rozwiązania:

Listing 1. Przykład zastosowania lazy

class Invoice{

    val number:Long by lazy {
        Random().nextLong()
    }

}

lazy przyjmuje jako parametr blok kodu (lambdę), który będzie inicjować naszą zmienną.

Wzorzec obserwatora

Jak wiemy, delegaty mogą obsługiwać nie tylko inicjację pola, ale też zmianę jego stanu. Naturalną konsekwencją takiego stanu rzeczy jest użycie delegata w roli obserwatoraW.

Listing 2. Przykładowy obserwator

class Invoice {

    //...

    var status: Status by Delegates.observable(NEW){
        prop, old, new ->
        println("Invocie $number has new status $new changed from $old")
    }

}

W ten sposób możemy w banalny sposób implementować obserwatora dla naszej wartości. Nasza funkcja zostanie uruchomiona PO ustawieniem nowej wartości.

Liberum Veto i chuj

Dawno wulgaryzmu nie było :D, a na serio. Jedną z form obserwatora jest tzw. obserwator walidujący albo inaczej obserwator wetujący. Różnica w stosunku do wyżej opisanego obserwatora polega na tym, że jest on uruchamiany PRZED ustawieniem nowej wartości.

Listing 3. Obserwator wetujący

class Invoice {

    var discount: Double by Delegates.vetoable(0.0) {
        prop, old, new ->
        new >= 0.0
    }
}

W tym przypadku funkcja musi zwracać wartość logiczną. Przy czym zwrócenie false nie powoduje wyrzucenia wyjątku. Jeżeli nieprawidłowe wartości chcemy obsługiwać za pomocą wyjątków, to samodzielnie musimy zadbać o ich wyrzucenie.

Nie będziesz null

Ostatnim delegatem dostępnym w standardowej bibliotece kotlina jest notNull. Jeżeli będziemy chcieli pobrać wartość, która będzie null, to dostaniemy ISE:

Listing 4. Delegat weryfikujący null

class Invoice {
  
    var address:String by Delegates.notNull<String>()
}

Podsumowanie

I tak oto kończymy tydzień z delegatami. Mechanizm ten daje nam wiele możliwości, ale ma też pewne wady. Zatem używanie go może być nieopłacalne, a szkoda, bo sam pomysł jest bardzo fajny.