Wzorzec
Delegacja
(Delegation
) jest wzorcem stanowiącym alternatywę dla implementacji przez dziedziczenie
i polega na tym, że klasa dziedzicząca zamiast implementować zachowanie deleguje je do wstrzykniętego obiektu. Wiele wzorców projektowych m.in. Strategia
, Wizytor
, Obserwator
w swym działania wykorzystują wzorzec Delegacja
. Kotlin
natywnie wspiera implementacje wzorca Delegacja całkowicie redukując powtarzający się kod (boilerplate
). Klasa wykorzystująca wzorzec Delegacja musi w swojej implementacji wstrzyknąć obiekt delegata oraz wskazać go w definicji za pomocą słowa kluczowego by
.
Nadpisywanie
Klasy implementujące wzorzec Delegacja mogą rozszerzyć lub zrezygnować z implementacji obiektu delegata poprzez nadpisanie wybranego członka klasy. Należy jednak mieć na uwadze, że implementacja nadpisanych właściwości nie jest widoczna dla delegata.
Właściwości
Właściwości delegowane
(delegated properties
) są mechanizmem dzięki któremu można delegować wywołanie metod akcesorów właściwości get
oraz set
do innego obiektu co odbywa w sposób zautomatyzowany. Implementacja jest jednorazowa eliminując potrzebę każdorazowego ręcznego przypisania. Kotlin wspiera właściwości delegowane za pomocą: leniwych właściwości (lazy properties
), oberwowalnych właściwości (observable properties
) oraz przechowywania właściwości w mapie. Aby zadeklarować właściwość jako delegowaną należy po nazwie oraz typie użyć słowa kluczowego by
, a następnie podać wyrażenie reprezentujące delegata, który musi dostarczyć implementację metod getValue
oraz setValue
co przedstawia się następująco.
Wywołanie akcesorów właściwości delegowane jest do metod getValue i setValue delegata, które mogą zostać dostarczone jako funkcje klasy, funkcje rozszerzające czy też implementacje interfejsów ReadOnlyProperty
lub ReadWriteProperty
. Delegowanie właściwości może mieć miejsce nie tylko dla właściwości klasy, ale także dla zmiennych lokalnych.
Leniwa właściwość
Funkcja lazy
przyjmuje wyrażenie lambda i zwraca instancje typu Lazy<T>
, która pełni rolę delegata dla właściwości. Pierwsze wywołanie get uruchamia wyrażenie lambda i zapamiętuje rezultat dzięki czemu kolejne odwołania zwracają zapamiętaną już wartość. Domyślnie obliczanie wartości jest w trybie synchronizowanym, tzn. odbywa się w jednym wątku przez co wszystkie wątki mają tą samą wartość. Aby wybrać tryb ręcznie należy przekazać do funkcji lazy jeden z parametrów LazyThreadSafetyMode
: SYNCHRONIZED
, PUBLICATION
, NONE
.
Obserwowalna właściwość
Funkcja Delegates.observable
przyjmuje dwa argumenty: wartość początkową oraz uchwyt do modyfikacji właściwości, który jest wywoływany przy każdym przypisaniu wartości do właściwości. Słuchacze są powiadamiani o zmianach we właściwości. Uchwyt opisany jest trzema parametrami: właściwość, stara wartość oraz nowa wartość. Użycie funkcji Delegates.vetoable
umożliwia przechwytywanie przypisania.
Przechowywanie w Map
W dynamicznych procesach jak np. parsowanie formatów warto wykorzystać przechowywanie właściwości w Map
(MutableMap
dla zmiennych var), która zamiast separowania pola dla każdej właściwości może pełnić rolę delegata dla wielu właściwości. Klucze elementów mapy muszą mieć taka samą nazwę co właściwość.