Temat dziedziczenia zakończyliśmy oficjalnie! Weźmiemy teraz pod lupę dodatek do wątku dziedziczenia, abyście mieli już pełnię możliwości do wykorzystania. Przedstawiam Wam słowo kluczowe "interface" w języku Kotlin jako sposób definiowania interfejsów, takich samych jak w Javie.

"INTERFACE" W JĘZYKU KOTLIN. SZTUKA DEFINIOWANIA INTERFEJSÓW

Najsampierw trzeba poznać definicję interfejsu i sens jego użycia. Najkrócej pisząc, interfejs jest zestawem abstrakcyjnych metod wymagających każdorazowej implementacji przez każdą klasę implementującą. Zgodnie z poznaną naturą metod abstrakcyjnych, nie zawierają one ciała dzięki czemu każda klasa ma obowiązek dostosować instrukcje do swoich potrzeb.

Interfejsy są doskonałe w sytuacjach, kiedy dwie klasy niebędące ze sobą powiązane w hierarchii dziedziczenia, posiadają wspólne zachowania, które można zaprogramować tak samo albo bardzo podobnie. Wykorzystując tę cechę interfejsów, jesteśmy w stanie konstruować instrukcje, które będą polimorficznie związane właśnie poprzez interfejs, gdyż z racji "wymuszania" implementacji, kompilator będzie miał pewność, że nie dojdzie do sytuacji, w której gdzieś tej metody zabraknie, a interfejs został zaimplementowany.

Nie zdziwi Was pewnie fakt, iż Kotlin raz kolejny demonstruje podążanie własną ścieżką i "nagina" pewne zasady jakie występują w Javie. Dojdziemy do nich jak zwykle porównując obok siebie Kotlina i Javę. Gdyby ktoś chciał poszerzyć zakres w tym kierunku, tutaj zostawiam odnośnik do artykułu na temat interfejsów w Javie. Najpierw składnia.

DEFINICJA INTERFEJSU

Jeśli chodzi o samo tworzenie interfejsu, nie ma żadnych różnic w porównaniu do "starszego brata". Oto najprostszy "interface" w języku Kotlin. To samo słowo kluczowe i klamerki:

interface Test
{
	
}

Wewnątrz można wprowadzać nagłówki metod, które mają wchodzić w skład późniejszej implementacji wewnątrz klasy, która będzie implementować ten interfejs. Oto przykład:

interface Test
{
	fun test()
}

co w Javie prawdopodobnie wyglądałoby tak:

public interface Test
{
	void test();
}

Sytuacja, w której "interface" w języku Kotlin dysponuje funkcją, która ma zwracać wartość? Nie ma sprawy:

interface Test
{
	fun test() : Float
}

a Java bardzo podobnie:

public interface Test
{
	float test();
}

IMPLEMENTACJA PRZEZ KLASĘ

Jak wspomniałem, klasa może bez problemu implementować interfejs i to nawet wiele interfejsów pod rząd, co stanowi duży plus w przeciwieństwie do klas, kiedy można dziedziczyć tylko od jednej. Kiedy chcemy, aby klasa IMPLEMENTOWAŁA interfejs (nie od niego dziedziczyła!), nie stosujemy słowa kluczowego "implements" jakie panuje w języku Java, tylko...po prostu wstawiamy dwukropek:

class Shape : Test
{
	override fun test()
	{
		println("Własna implementacja metody interfejsu!")
	}
}

Notabene, że nie umieszczacie ŻADNYCH nawiasów po nazwie! "interface" w języku Kotlin nie wymaga nawiasów. Nie dysponuje konstruktorem, a zatem żadnych nawiasów tam nie ma. Ponieważ w interfejsie znajdują się zwykle metody abstrakcyjne, trzeba je przesłonić i wprowadzić niestandardową implementację, o czym już napisałem kilkakrotnie. Dlatego macie "override". A w porównaniu do Javy:

public class Shape implements Test
{
	@Override
	public void test()
	{
		System.out.println("Własna implementacja metody interfejsu!");
	}
}

nie powinno być już wątpliwości czemu tak, a nie inaczej.

KONWENCJA NAZEWNICZA

Dosłownie kilka zdań o istotnym punkcie jakim jest konwencja nazewnicza. Jeśli chodzi o kompilator, wszystko mu jedno czy nadacie taką albo śmaką nazwę. Jest jednak panująca w środowisku rynkowym reguła, że wszelkie nazwy interfejsów powinny określać co on robi albo po co został stworzony. Technicznie rzecz biorąc, chodzi o stosowanie słów z końcówką "-ible" lub "-able" (jeśli nazwy są pisane w języku angielskim), na przykład "Damageable", bądź "Lockable". Nikt Wam nie ukręci głowy za bycie oryginalnym, natomiast warto wiedzieć, że jakaś zasada istnieje i cóż...nie muszę pisać, że przydałoby się jej przestrzegać.

A teraz przyjrzyjmy się temu, czego Java NIE może, a Kotlin oferuje.

ROZSZERZONA MOŻLIWOŚĆ W KOTLINIE

Aby dodać "smaczku" do tego artykułu, pokażę Wam co możecie zrobić stosując "interface" w języku Kotlin, a co w Javie zostanie uznane za niedopuszczalne.

IMPLEMENTACJE METOD

To jest punkt pierwszy. Metody zwykle powinny być abstrakcyjne, bo tylko wówczas interfejsy są naprawdę użyteczne jednakże w Kotlinie zezwala się również na implementacje metod WEWNĄTRZ interfejsu! Innymi słowy, to może być zwykła funkcja siedząca sobie po cichutku w interfejsie niewymagająca implementacji w każdej klasie, która ten interfejs wykorzystuje (choć nadal będzie mogła być przesłonięta bez żadnych dodatków). To jest przykład:

interface Test
{
	fun test()
	{
		println("Implementacja funkcji w środku interfejsu!")
	}
}

Przy użyciu implementacji wewnątrz interfejsu, obowiązek implementacji tej samej funkcji na zewnątrz w każdej klasie implementującej, zostaje zniesiony.

AKCESORY I MUTATORY

Drugi punkt to informacja o możliwości korzystania z danych składowych również WEWNĄTRZ interfejsów! Co prawda, w Javie to żadna nowość i tam też można wstawiać zmienne, aczkolwiek macie również do dyspozycji "gettery" i "settery" opisane już jakiś czas temu.

Słowo kluczowe "interface" w języku Kotlin

Słowo kluczowe "interface" w języku Kotlin nie różni się niczym w porównaniu do języka Java, jedynie oferuje więcej możliwości i dopuszczalnych manewrów.


Interfejsy są znakomitą opcją na łączenie ze sobą klas poprzez zachowanie, nie hierarchię. Dzięki postulatowi polimorfizmu, można dla przykładu opakować kilka obiektów różnych klas do tablicy typu "nasz interfejs" i iterując po każdym elemencie, wywoływać tę samą metodę, która będzie kierować się własną implementacją zawartą w klasie.

PODOBNE ARTYKUŁY