Historia pytania:
Kotlin łączy najlepsze cechy Javy i dziedzictwa funkcjonalnego JVM. Zwykłe klasy są ogłaszane jako standardowe struktury, klasy abstrakcyjne pozwalają na tworzenie niedookreślonych szablonów z domyślną implementacją, a interfejsy obsługują wielokrotne dziedziczenie zachowań bez stanu.
Problem:
Właściwy wybór między klasą, klasą abstrakcyjną a interfejsem określa architekturę aplikacji, granularność kodu i jego rozszerzalność. Niewłaściwe dziedziczenie prowadzi do trudności w testowaniu i przyszłych zmianach.
Rozwiązanie:
W Kotlinie:
Przykład kodu:
interface Drawable { fun draw() } abstract class Shape(var color: String) : Drawable { abstract fun calcArea(): Double override fun draw() = println("Shape drawn") } class Circle(color: String, val radius: Double) : Shape(color) { override fun calcArea() = Math.PI * radius * radius }
Kluczowe cechy:
Czy interfejsy mogą zawierać właściwości z backing field?
Nie, mogą definiować tylko sygnaturę właściwości, ale nie przechowywać danych – właściwości bez pola backing field.
Czy można dziedziczyć z kilku klas?
Nie, Kotlin obsługuje tylko pojedyncze dziedziczenie klas, ale wielokrotną implementację interfejsów.
Czy można zadeklarować konstruktor w interfejsie?
Nie, interfejs nie obsługuje konstruktorów, ponieważ nie przechowuje stanu – tylko kontrakt zachowania.
W aplikacji wszystkie wspólne funkcje przeniesiono do klasy abstrakcyjnej, nawet jeśli nie miały wewnętrznej logiki ani stanu, a potrzeba była tylko wspólnym kontraktem.
Zalety:
Wady:
Przeniesiono tylko potrzebne kontrakty do interfejsów, klasy abstrakcyjne ograniczono do wspólnych właściwości i metod wymagających implementacji.
Zalety:
Wady: