Obiekty towarzyszące
Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 13 z 57.
Niektóre elementy należą do klasy jako całości, a nie do jednej instancji. Kotlin umieszcza je w obiekcie companion object wewnątrz klasy, a wywołujesz je za pomocą nazwy klasy:
class Temperature(val celsius: Double) {
companion object {
fun fromFahrenheit(f: Double) = Temperature((f - 32) * 5 / 9)
}
}Wewnątrz main:
val boiling = Temperature.fromFahrenheit(212.0)
println(boiling.celsius)Wynik:
100.0fromFahrenheit to funkcja fabrykująca: funkcja, która tworzy instancje. W przeciwieństwie do konstruktora ma opisową nazwę i może zwrócić null zamiast obiektu. Dzięki private constructor fabryka jest jedynym sposobem tworzenia obiektów, więc może najpierw sprawdzić i oczyścić dane wejściowe:
class Username private constructor(val text: String) {
companion object {
fun of(raw: String): Username? {
val clean = raw.trim().lowercase()
return if (clean.length in 3..12) Username(clean) else null
}
}
}Wewnątrz main:
println(Username.of(" Ada_L ")?.text)
println(Username.of("x")?.text)
// Username("x") // błąd: konstruktor jest prywatnyWynik:
ada_l
nullObiekt towarzyszący należy do klasy, więc może wywoływać prywatny konstruktor, a kod samej klasy korzysta z elementów obiektu towarzyszącego bez przedrostka. Tutaj każdy bilet otrzymuje kolejny numer z jednego licznika współdzielonego przez wszystkie bilety:
class Ticket(val holder: String) {
val number = nextNumber++
companion object {
private var nextNumber = 1
val issued: Int
get() = nextNumber - 1
}
}Wewnątrz main:
val a = Ticket("Ada")
val b = Ticket("Bo")
println("${a.holder} #${a.number}, ${b.holder} #${b.number}")
println("issued: ${Ticket.issued}")Wynik:
Ada #1, Bo #2
issued: 2Kotlin nie ma słowa kluczowego static. Członkowie obiektu towarzyszącego pełnią tę rolę: jedna kopia dla całej klasy, dostępna jako ClassName.member. Podobnie jak każdy obiekt, obiekt towarzyszący jest tworzony raz, gdy klasa zostaje użyta po raz pierwszy. Umieść w nim elementy, które nie zależą od konkretnej instancji, takie jak fabryki i współdzielone liczniki; wszystko, co odczytuje dane instancji, pozostaje zwykłym członkiem.
class User private constructor(val name: String) {
fun greet() = "hi $name" // wymaga instancji: user.greet()
companion object {
fun guest() = User("guest") // należy do klasy: User.guest()
}
}Wyzwanie
ŁatwyUzupełnij klasę Coupon. Jej konstruktor jest prywatny, więc kupony są tworzone przez fabrykę Coupon.create(code, percent) w obiekcie towarzyszącym. Zwraca ona null, chyba że kod składa się z 4 do 10 wielkich liter i cyfr, a wartość procentowa mieści się w zakresie od 1 do 90. Obiekt towarzyszący zlicza też utworzone kupony w created; kod zewnętrzny może odczytać tę wartość, ale nie może jej zmienić. apply(price) zwraca cenę pomniejszoną o rabat, zaokrągloną w dół (price * (100 - percent) / 100).
Dostarczony kod odczytuje wiersze SAVE10 10 200 (kod, wartość procentowa, cena). Wypisuje SAVE10: 180 lub invalid coupon SAVE10, a na końcu created: wraz z liczbą kuponów.
Twój kod umieść w Coupon.kt. Plik Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.
Spróbuj swoich sił
fun main() {
// Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
val input = generateSequence(::readLine).toList()
for (line in input) {
val (code, percent, price) = line.split(" ")
val coupon = Coupon.create(code, percent.toInt())
if (coupon == null) println("invalid coupon $code") else println("${coupon.code}: ${coupon.apply(price.toInt())}")
}
println("created: ${Coupon.created}")
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Klasy i obiekty
Praca z plikamiDefiniowanie klasKonstruktory główneBloki init i walidacjaKonstruktory dodatkowePodsumowanie — karta biblioteczna4Dziedziczenie
Klasy otwarte i podklasyNadpisywanie składowychsuper i konstruktoryKlasy abstrakcyjnePodsumowanie – katalog pracowników7Klasy specjalne
Klasy danychKlasy wyliczenioweHierarchie zapieczętowaneequals, hashCode, toStringPodsumowanie — śledzenie zamówień10Wzorce projektowe, część 2
Delegowanie za pomocą byWzorzec dekoratoraWzorzec budowniczegoWzorzec stanu2Właściwości i hermetyzacja
Własne akcesoryModyfikatory widocznościPrywatne setterylazy i lateinitPowtórka – konto bankowe5Interfejsy
Deklarowanie interfejsówMetody domyślneWiele interfejsówInterfejsy jako typyPowtórzenie – metody płatności8Typy generyczne
Funkcje generyczneKlasy generyczneOgraniczenia typówKowariancja i kontrawariancja: in i outPodsumowanie — kolejka priorytetowa11Projekt: Zarządzanie biblioteką
Książki i czytelnicyWypożyczanie książek3Obiekty i obiekty towarzyszące
Deklaracje obiektówObiekty towarzysząceStałe z constWyrażenia obiektowePowtórzenie — kasa biletowaPoćwicz samodzielnie: Edytor online Kotlin