IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 16 - Rozhraní (interface) v Kotlin

V předešlém cvičení, Řešené úlohy k 10.-15. lekci OOP v Kotlin, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

Dnes to bude opět trochu teoretické, objevíme další taje objektově orientovaného programování, uvedeme si totiž rozhraní.

Rozhraní

Rozhraním objektu se myslí to, jak je objekt viditelný zvenku. Již víme, že objekt obsahuje nějaké metody, ty mohou být privátní nebo veřejné. Rozhraní objektu tvoří právě jeho veřejné metody, je to způsob, jakým s určitým typem objektu můžeme komunikovat. Již jsme několikrát mohli vidět jaké veřejné metody naše třída nabízí, např. u našeho bojovníka do arény. Třída Bojovnik měla následující veřejné metody:

  • utoc(souper: Bojovnik)
  • branSe(uder: Int)
  • nazivu(): Boolean
  • nastavZpravu(zprava: String)
  • vratPosledniZpravu(): String
  • grafickyZivot(): String

Pokud si do nějaké proměnné uložíme instanci bojovníka, můžeme na ni volat metody jako utoc() nebo branSe(). To pořád není nic nového, že?

My si však rozhraní můžeme deklarovat zvlášť a to podobným způsobem jako třeba třídu. Toto rozhraní poté použijeme jako datový typ.

Vše si vyzkoušíme, ale na něčem jednodušším, než je bojovník. Vytvořme si nový projekt a nazvěme ho Rozhrani. Přidáme si nějakou jednoduchou třídu. Protože by se dle mého názoru měla teorie vysvětlovat na něčem odlehčujícím, uděláme si Ptáka. Bude umět pípat, dýchat a klovat. Přidejme si třídu Ptak, bude vypadat takto:

class Ptak {

    fun pipni() {
        println("♫ ♫ ♫")
    }

    fun dychej() {
        println("Dýchám...")
    }

    fun klovni() {
        println("Klov, klov!")
    }

}

Třída je opravdu triviální. Přejděme do Main.kt a vytvořme si instanci ptáka:

val ptak = Ptak()

Nyní napíšeme ptak. a necháme IntelliJ, aby nám zobrazil metody na třídě (lze také vyvolat stiskem Ctrl + Space):

Metody na třídě Ptak - Objektově orientované programování v Kotlin

Vidíme, co na ptákovi můžeme vše volat. Jsou tam samozřejmě ty 3 metody, co jsme ve třídě implementovali (plus další, které mají objekty v základu).

Nyní ptákovi vytvoříme rozhraní. Využijeme k tomu klíčového slova interface (anglicky rozhraní). Pojmenování rozhraní v Kotlinu je poměrně věda (stejně jak v Javě). My se spokojíme s názvem PtakInterface. Pravým tlačítkem klikneme na projekt a přidáme "New" -> "Kotlin File/Class". V dropdown menu vybereme Interface.

Nový interface v Kotlinu - Objektově orientované programování v Kotlin

K projektu se nám přidá prázdný interface. Do něj přidáme hlavičky metod, které má dané rozhraní obsahovat. Samotnou implementaci (kód metod) uvedeme až ve třídě, která bude toto rozhraní implementovat (viz dále).

Kotlin, stejně jako Java od verze 8, umožňuje uvádět v rozhraní i těla metod, tedy jejich kód. To je proti tomu, co si zde dnes budeme vysvětlovat, a tato funkcionalita vznikla z důvodu podpory tzv. traitů. S těmi se pracuje jinak než s interfacem a jazyky jako jsou např. PHP nebo Scala mají pro tuto funkcionalitu vlastní klíčové slovo trait.

Do rozhraní PtakInterface tedy přidáme hlavičky metod, schválně jednu vynecháme a přidáme pouze Pípání a Dýchání:

interface PtakInterface {
    fun pipni()
    fun dychej()
}

Rozhraní obsahuje vždy pouze veřejné metody (jinak by nemělo smysl, udává, jak s objektem zvenku pracovat).

Vraťme se do Main.kt a změňme řádek s proměnnou ptak tak, aby již nebyla typu Ptak, ale PtakInterface:

val ptak: PtakInterface = Ptak()

Kódem výše říkáme, že v proměnné typu PtakInterface očekáváme objekt, který poskytuje ty metody, co jsou v rozhraní. Kotlin nám vyhubuje, protože třída Ptak zatím rozhraní PtakInterface neimplementuje, i když potřebné metody má, neví, že rozhraní poskytuje. Přesuneme se do třídy Ptak a nastavíme jí, že implementuje interface PtakInterface. Implementovaným metodám dodáme klíčové slovo override (stejně jako u dědičnosti). Interface se implementuje operátorem ::

class Ptak: PtakInterface {
    override fun pipni() {
        println("♫ ♫ ♫")
    }

    override fun dychej() {
        println("Dýchám...")
    }

    fun klovni() {
        println("Klov, klov!")
    }
}

Když se nyní vrátíme do Main.kt, řádek s proměnnou typu PtakInterface je již v pořádku. Třída Ptak korektně implementuje rozhraní PtakInterface a její instance může být do proměnné tohoto typu uložena.

Zkusme nyní vymazat ze třídy nějakou metodu, kterou rozhraní udává, např. pipni(). IntelliJ nás upozorní, že implementace není kompletní. Vraťme ji zas zpět.

Opět přidáme řádek ptak., IntelliJ nám nabídne následující metody:

Metody ptáka s rozhraním PtakInterface - Objektově orientované programování v Kotlin

Vidíme, že na instanci můžeme nyní volat pouze metody, které poskytuje rozhraní. To proto, že proměnná ptak je již typu PtakInterface, nikoli Ptak. Metoda klovni() úplně chybí.

K čemu je to dobré? Výhod a využití je více, na první jsme již přišli. Pomocí rozhraní dokážeme zjednodušit rozhraní nějakého složitého objektu a vystavit jen tu část, která se nám v tu dobu hodí.

Ještě dodám, že nemůžeme vytvořit instanci z rozhraní, tento kód nebude fungovat:

// tento kód nebude fungovat
val ptak: PtakInterface = PtakInterface()

Vícenásobná dědičnost

Kotlin (stejně jako většina jazyků) nepodporuje vícenásobnou dědičnost. Nemůžeme tedy jednu třídu oddědit z několika jiných tříd. Je to hlavně z toho důvodu, že může vyvstat problém kolize názvů metod v různých třídách, ze kterých dědíme (Diamond problem). Vícenásobná dědičnost se často obchází právě přes interface, protože těch můžeme ve třídě implementovat kolik chceme. Umožňuje nám to s instancí poté pracovat určitým způsobem a vůbec nás nezajímá, jakého typu objekt ve skutečnosti je a co všechno navíc obsahuje.

Přidejme si k projektu interface JesterInterface. Bude to interface ještěra. Ten bude umět také dýchat a ještě se plazit:

interface JesterInterface {
    fun plazSe()
    fun dychej()
}

Vyzkoušejme si "vícenásobnou dědičnost", přesněji implementaci více rozhraní v jedné třídě. Udělejme si ptakoještěra. Přidejme k projektu třídu PtakoJester. Bude implementovat rozhraní PtakInterface a JesterInterface:

class PtakoJester: JesterInterface, PtakInterface {
}

Když nyní klikneme na ikonu žárovky, můžeme v kontextovém menu zvolit možnost "Implement members". IntelliJ nám automaticky do třídy vygeneruje potřebné metody.

Implementace Interfacu - Objektově orientované programování v Kotlin

Po implementaci obou rozhraní vypadá kód třídy takto:

class PtakoJester: JesterInterface, PtakInterface {
    override fun pipni() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun plazSe() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun dychej() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}

Metody v ještěrovi doimplementujeme:

override fun pipni() {
    println("♫ ♫♫ ♫ ♫ ♫♫")
}

override fun plazSe() {
    println("Plazím se...")
}

override fun dychej() {
    println("Dýchám...")
}

Přesuňme se do Main.kt a vytvořme si instanci ptakoještěra:

val ptakoJester = PtakoJester()

Ujistěme se, že má metody jak ptáka, tak ještěra:

Metody ptáka a ještěra - Objektově orientované programování v Kotlin

V příští lekci, Přetypování a hierarchie objektů v Kotlin, se budeme dále věnovat rozhraní a naučíme se další pokročilé techniky objektově orientovaného programování.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 24x (23.18 kB)
Aplikace je včetně zdrojových kódů v jazyce Kotlin

 

Předchozí článek
Řešené úlohy k 10.-15. lekci OOP v Kotlin
Všechny články v sekci
Objektově orientované programování v Kotlin
Přeskočit článek
(nedoporučujeme)
Přetypování a hierarchie objektů v Kotlin
Článek pro vás napsal Samuel Kodytek
Avatar
Uživatelské hodnocení:
10 hlasů
Autor se věnuje všem jazykům okolo JVM. Rád pomáhá lidem, kteří se zajímají o programování. Věří, že všichni mají šanci se naučit programovat, jen je potřeba prorazit tu bariéru, který se říká lenost.
Aktivity