DEV Community

Konrad Chmielecki
Konrad Chmielecki

Posted on • Updated on

[kotlin] interfejsy

W kotlinie szukam takiego rozwiązania które pomoże mi dążyć do płaskiej struktury obiektów.
Do tego celu między innymi nadają się interfejsy które można dodawać przy tworzeniu klasy. W przypadku kotlina interfejsy pozwalają na zagnieżdżanie kodu. Dzięki czemu klasa nie musi definiować własnej metody, tylko może zaczerpnąć ją z interfejsu.

Krótki przykład tworzenia kompozycji.

interface A {
    fun fooA() {
        println("Jestem z interfejsu A")
    }
}

interface B {
    fun fooB() {
        println("Jestem z interfejsu B")
    }
}

class Foo:A,B
Enter fullscreen mode Exit fullscreen mode

W przypadku gdy chce stworzyć łańcuch funkcji muszę użyć this
Jednakże problem jest taki że interfejsy nie wiedzą o sobie na wzajem. Więc za każdym razem musiałbym zwracaną referencję zamieniać na utworzoną klasę. Co raczej nijak ma się do łańcucha funkcji.
Z pomocą przychodzą typy generyczne które funkcje mogą zwracać.
Ale zanim to nastąpi this musi zostać zamieniony na typ generyczny.

interface A<out T> {
    fun fooA():T {
        println("Jestem z interfejsu A")
        return this as T
    }
}

interface B<out T> {
    fun fooB():T {
        println("Jestem z interfejsu B")
        return this as T
    }
}

class Foo:A<Foo>,B<Foo>
Enter fullscreen mode Exit fullscreen mode

Jak widać utworzona klasa Foo przekazuje samą siebie do interfejsów. Dzięki czemu funkcje w interfejsach będą zwracały instancję klasy Foo.
Niestety wadą tego rozwiązania jest brak możliwości hermetyzacji.
Kolejny problem to niemożliwość stworzenia kopi zmiennych i przekazanie ich do tej samej klasy. Wiec można pracować tylko na referencji klasy.

Jeżeli w interfejsie są zdefiniowane jakieś zmienne to należy zdefiniować je w tworzonej klasie używając instrukcji override.
To samo należy zrobić przy tworzeniu własnej definicji metod która znajduje się w interfejsie.
Można w interfejsach definiować wartości stałych przy użyciu getter.
W tedy nie trzeba dodawać przeciążenia takiej stałej w klasie.

interface A {
    val foo:Int
        get() = 1
}
Enter fullscreen mode Exit fullscreen mode

Wymóg używania override jest dość upierdliwe zwłaszcza przy data class.
Ale to pokazuje że interfejsy w kotlinie są pewnego rodzaju klasą abstrakcyjną z pewnymi ograniczeniami.

Discussion (0)