Jason. Cała informatyka w jednym miejscu!

Czy jesteście gotowi na kolejną cześć poznawania Kotlina? Niech nie zepsuje Wam nastroju wiadomość, że zaprezentuję kolejną innowację której nie znajdziecie w calutkiej Javie, chociaż możecie ją kojarzyć z innego języka, o którym można napisać że jest "spokrewniony". Przedstawiam Wam "get" i "set" w języku Kotlin, czyli akcesory i mutatory.

"GET" I "SET" W JĘZYKU KOTLIN. NAWIĄZANIE DO CSHARP'A

Te dwa słówka mogą być znajome użytkownikom języka C#. Dlatego wspomniałem o nim jak o spokrewnionym z Javą (faktycznie tak jest!). Przechodząc do rzeczy, "get" i "set" pozwalają na manipulację właściwością (daną składową klasy) edytując wartość zwracaną ("get") i wartość przypisywaną ("set"). Wszystko wyjaśnię po kolei, a na razie skupmy się na użyteczności.

ZASTOSOWANIE

Użycie "get" i "set" w języku Kotlin pozwala uniknąć definiowania funkcji mających na celu jedynie ustawianie i zwracanie wartości danej składowej. Pamiętacie z Javy?

void setAttribute(int value) {
	attribute = value;
}

int getAttribute() {
	return attribute;
}

Upierdliwe. A jak przemnoży się to przez liczbę danych składowych, które potrzebują zarówno modyfikacji, jak i zwracania? Boże Święty!!!

Tym komicznym podejściem dotarliśmy do powodu korzystania z wyżej wymienionych słów. Pozwalają "wyrazić" to samo pożądane przez nas zachowanie, tylko...po prostu ładniej. Oba słówka wprowadza się tak jakby pod zdefiniowaną daną składową. Na poniższych przykładach możecie zobaczyć o co mi chodzi.

Bywa tak, że "get" jest nazywany "akcesorem", a "set", "mutatorem". Czasami ludzie określają oba "akcesorami". Przez resztę artykułu będę się trzymał osobnych pojęć celem większego zróżnicowania. Przejdźmy teraz do prezentacji jednego i drugiego.

AKCESOR "GET"

Najpierw akcesor. Jest on dostępny zarówno dla zmiennych zdefiniowanych ze słowem kluczowym "var", jak i tych z "val". A tak wygląda składnia:

val attribute = 0
	get() {
		return field
	}

Muszę przykuć Waszą uwagę na słowo kluczowe "field". "get" i "set" w języku Kotlin nie korzystają z nazw właściwości do których należą, tylko korzystają z obejścia o nazwie "field". Ten cosik jest nazywany "polem wspierającym" i oznacza on odniesienie (referencję) do wartości występującej po znaku przypisania.

Powyższy zapis tak naprawdę nic nie daje, bo to jest to samo, co "val" z przypisaną wartością zero bez tego dodatku poniżej. Możemy nakazać akcesorowi zwracać jakieś wyrażenie tak jak przy użyciu funkcji zwracającej. To jest przykład akcesora kalkulującego hipotetyczne pole prostokąta:

val area
	get() {
		return a*b
	}

Zanim przejdziemy do drugiego ancymona, uwaga! Kotlin dopuszcza możliwość zdefiniowania akcesora w skróconej formie przypominającej znowu wyrażenie lambda:

val area
	get() = a*b

oczywiście pod warunkiem, że kończy się tylko na instrukcji "return". Możemy też wszystko umieścić w jednej linijce:

val area get() = a*b

Od tej pory, właściwość "area" będzie zachowywała się jak funkcja zwracająca iloczyn boku a i b. Kiedy utworzymy sobie taki akcesor, to korzystamy z niego DOKŁADNIE tak samo, jak "z tradycyjnych" danych składowych – operator kropki i nazwa:

println(rectangle.area)

Powyższe wywołanie "wypluje" wynik mnożenia obu boków.

MUTATOR "SET"

Teraz "set", czyli mutator. Przyjmuje on jeden parametr najczęściej nazywany "value" i w domyślnej strukturze obejmuje jedną instrukcję w postaci przypisania wartości parametru do siebie samego, czyli do "field" (broń Boże wstawiać tam identyczną nazwę właściwości, bo program wpadnie w nieskończoną rekurencję i się wyłoży!!!):

var attribute = 0
	set(value) {
		field = value
	}

Zastosowanie? Ważniejsze niż możecie wstępnie przypuszczać. "get" i "set" w języku Kotlin to potężne bronie w rękach programisty, które efektywnie zredukują ilość kodu zachowując nasze zamiary w takim samym stanie. Oprócz przypisywania nowej referencji, możemy wpływać na to kiedy ona powinna zajść! Dajmy na to, że mamy ten nasz prostokąt i chcemy mieć możliwość przypisania innych wartości obu boków. Na chwilę obecną, możemy zrobić tak:

rectangle.x = -5

Oj! To nie będzie wróżyło niczego dobrego. W takiej sytuacji mamy dwa rozwiązania: albo zmieniamy typ danych na "UInt", czyli "liczba całkowita bez znaku" (tak, Kotlin wspiera wersje zmiennych "unsigned" znane z języka C!), albo zabronić przypisywania wartości jeśli nie są większe od zera:

var a = 0
	set(value) {
		if(value > 0) {
			field = value
		}
	}

Gotowe! Od teraz, jak przypiszemy wartość dodatnią np. 7, wtedy obiekt zostanie zamieniony. Kiedy jednak dorzucimy -3 dla przykładu, wtedy nic nie ulegnie zmianie. Mutator będzie "głuchy" na nasze prośby i będzie miał gdzieś przypisywanie wartości ujemnych, gdyż modyfikacja jest objęta instrukcją warunkową. "set" jest doskonałym rozwiązaniem na przejęcie kontroli nad przypisywaniem nowych wartości odpowiednim danym składowym. A ze względu na swoją rolę, może on zostać zdefiniowany wyłącznie dla danej składowej z użyciem słowa "var".

Słowa kluczowe "get" i "set" w języku Kotlin

Korzystanie z akcesorów i mutatorów jest alternatywnym podejściem definiowania funkcji, których jedynym zadaniem jest przypisywanie i pobieranie wartości z określonych danych składowych.

A na końcu taka informacja, że słowa "get" i "set" w języku Kotlin są automatycznie generowane przez kompilator w postaci "trybów domyślnych", jeśli sami ich nie napisaliśmy. Oto jak to wygląda za kotarą. Tak w przypadku "var":

var attribute = [wartość]
	get() = field
	set() {
		field = value
	}

a tak w przypadku "val":

val attribute get() = [wartość]

Głowicie się czemu przy "val" może "stać" tylko akcesor? Przecież "val" zabrania późniejszego przypisywania nowej referencji! Przypominam o typach prostych, które także są obiektami więc zmiana liczbowej wartości to tak naprawdę próba przypisania nowej referencji do nowego obiektu, na co "val" za cholerę nie pozwoli.


Dzięki za przeczytanie. Kolejny bardzo ważny temat mamy z głowy. Pilnujcie się z tym i korzystajcie jak najczęściej, bo to może tylko pomóc skrócić kod.

PODOBNE ARTYKUŁY