Rozpoczynamy od dzisiaj rozdział związany z dziedziczeniem! Podzielimy to sobie na kilka artykułów, a każdy z nich będzie stanowił nowy element w całej układance. Dziedziczenie w języku Kotlin to już całkiem seryjny temat i dlatego wymaga fragmentacji, a to jest pierwsza część. Zapraszam!

DZIEDZICZENIE W JĘZYKU KOTLIN TO TEMAT NA DŁUŻSZĄ ROZMOWĘ

W tej części, opiszę do czego służy to dziedziczenie oraz jak je zaprogramować w Kotlinie. Choć jeśli umiecie Javę, to część nauki macie już odhaczoną na dzień dobry, gdyż zasada działania pozostaje taka sama. Tylko składnia będzie musiała być poznawana na nowo.

ZASTOSOWANIE

Parę zdań poświęcę na teorię. Dziedziczenie to jeden z postulatów paradygmatu obiektowego, który mówi o tym, że klasy mogą być ze sobą powiązane poprzez odziedziczanie danych składowych i metod od klas bazowych przez inne klasy (które de facto stają się wówczas klasami pochodnymi). Służy to maksymalnemu ograniczeniu nadmiarowości danych (powielenie tych samych lub bardzo podobnych zmiennych i funkcji) i zarazem udostępnia możliwość dostosowania lub delikatnej korekty w klasach pochodnych (przesłanianie), choć można zostawić w takiej samej formie bez zmian. Same klasy pochodne mogą dodać coś od siebie i być w posiadaniu własnych danych składowych i metod. Dobre zrozumienie dziedziczenia zapewni Wam pisanie efektywnego kodu, który będzie wymagać późniejszych edycji tylko w jednym miejscu, jeżeli będziecie pragnęli zmodyfikować zachowanie klasy, od której rozpoczyna się całe dziedziczenie.

JAK WYGLĄDA DZIEDZICZENIE?

Dziedziczenie w języku Kotlin wygląda prościej niż w języku Java. Zakładając, że mamy taką klasę otworzoną (może być również abstrakcyjna):

open class Point
{
	
}

i taką, którą chcemy uczynić pochodną:

class Entity
{
	
}

wystarczy zaraz po nazwie dodać dwukropek i nazwę klasy, od której ma dziedziczyć obecna:

class Entity : Point()
{
	
}

Tu zrobimy przystanek, bo ważne jest wspomnienie o konstruktorze klasy bazowej. Kiedy wykonujecie dziedziczenie w języku Kotlin, musicie podać parę nawiasów okrągłych, zaraz po nazwie klasy bazowej. Nawet, kiedy nie przyjmuje żadnych parametrów, to i tak dajecie nawiasiki. Jest to wymagane dlatego, iż w momencie tworzenia obiektu klasy pochodnej, musi wpierw zostać wykonany konstruktor klasy bazowej. Dopiero wtedy zostaje wykonany konstruktor klasy pochodnej.

Przykład konstruktora bezparametrowego już macie, a co w sytuacji posiadania jakichkolwiek parametrów, bądź danych składowych wewnątrz konstruktora?

open class Point(tx : Int, ty : Int)
{
	open var x = tx
	open var y = ty
}

class Entity(tx : Int, ty : Int) : Point(tx, ty)
{
	
}

Widzicie? Przenosimy te same parametry formalne do środka konstruktora klasy "Point", a one idą dalej swoim torem i trafiają w to samo miejsce. Możemy również bez problemu wprowadzić stałe wartości i tym sposobem wymigać się od wstawienia parametrów dla współrzędnych, jednak odbiłoby się to na wygodzie tworzenia obiektów. Za każdym razem będziecie wtedy zmuszeni do ręcznego przypisywania wartości współrzędnych "na uboczu".

Kolejną wielką zaletą jaką nam daje dziedziczenie w języku Kotlin jest możliwość przesłaniania właściwości i metod oraz implementacja własnych danych składowych i metod (albo nadpisanie już istniejących w ramach przesłaniania).

TWORZENIE OBIEKTU

Tworzenie obiektu na podstawie klasy wygląda PRAWIE tak samo jak w Javie. Jedyną różnicą jest brak słowa kluczowego "new" zaraz po nazwie:

val point = Point(3, 6)

Poza tym, reszta jest taka sama.

DODATKI W KLASIE POCHODNEJ

Kiedy chcemy, aby klasa pochodna posiadała własne dodatkowe dane, postępujemy identycznie jak przy klasie bazowej oraz na zewnątrz klasy. Po prostu definiujemy je:

class Entity(tx : Int, ty : Int, tmodel : String) : Point(tx, ty)
{
	val model = tmodel
	
	fun draw()
	{
		
	}
}

PRZESŁANIANIE

Przesłanianie polega na tym, że w klasie bazowej "oflagowujecie" właściwość lub metodę słowem "open", a w klasie pochodnej, słowem "override" i nadajecie nową wartość (albo treść funkcji):

open class Point(tx : Int, ty : Int)
{
	open var x = tx
	open var y = ty
	
	fun draw()
	{
		println("Rysuję punkt.")
	}
}

class Entity(tx : Int, ty : Int) : Point(tx, ty)
{
	override var x = 5
	override var y = 5

	override fun draw()
	{
		println("Rysuję jednostkę.")
	}
}

Gdy będziecie chcieli nie nadpisać, a "dołożyć" własne instrukcje do pierwotnej wersji, wystarczy wywołać tę samą metodę z przedrostkiem "super" (dotyczy to tylko klas pochodnych, które wykorzystują dziedziczenie w języku Kotlin). Przybliżę Wam składnię wycinając tylko interesujący fragment:

override fun draw()
{
	super.draw()
	println("Rysuję jednostkę.")
}

Spowoduje to wykonanie wszystkich instrukcji zawartych w tej samej metodzie w klasie bazowej ORAZ wykonanie wszystkich instrukcji w tej samej metodzie tutaj.

"AWANS" ZE SŁOWA "VAL" NA "VAR"

Dwa słowa o sztuczce której nie zrobicie w Javie. Jeżeli klasa bazowa posiada właściwość ze słowem "val":

open val attribute = 10

to możemy w klasie pochodnej "przetransformować" tę samą właściwość na słowo "var", o tak:

open var attribute = 16

czyniąc w ten sposób właściwość edytowalną dla tej klasy pochodnej, mimo tego że w klasie bazowej jest blokada przypisywania nowych referencji!

Od razu zaznaczam, że w drugą stronę robić nie wolno! Kompilator nie pozwoli właściwości ze słowem "var" zdegradować do słowa "val". Jak będzie można pozbawić się "settera" skoro występuje on w klasie bazowej? A postulat dotyczący dziedziczenia wskazuje właśnie na to, że każda klasa pochodna musi być w stanie robić wszystko to, co może klasa bazowa.

Dziedziczenie w języku Kotlin

Dziedziczenie w języku Kotlin wymaga korzystania z wielu słów kluczowych naraz. Ponadto, kieruje się innymi sposobami zapisu niż poprzednik.


To tyle na początek. W następnych artykułach będę przybliżać Wam każdy wątek z osobna, aby nic się nie pomieszało w głowach.

PODOBNE ARTYKUŁY