Klasa danych jest pojęciem niezwiązanym z żadnym konkretnym językiem programowania, jest to wzorzec, który jest wystarczająco wygodny dla większości programistów jako prosty sposób na reprezentowanie, Hermetyzowanie i przenoszenie informacji.

Klasa danych odnosi się do klasy, która zawiera tylko pola i metody crud dostępu do nich (gettery i settery). Są to po prostu kontenery dla danych używanych przez inne klasy. Klasy te nie zawierają żadnych dodatkowych funkcji i nie mogą samodzielnie działać na danych, które posiadają.

zazwyczaj klasy danych reprezentują rzeczywiste byty i często zdarza się, że w projekcie znajdują się dziesiątki lub setki takich klas, co oznacza, że tworzenie, modyfikowanie i manipulowanie tymi obiektami jest bardzo częstym zadaniem programisty.

Klasa danych w Javie

tak zwykle wygląda Klasa danych w Javie:

zauważysz, że nadpisujemy metody toString() , equals() i hashCode() (zadeklarowane w klasie Object.java). Dlaczego nadpisywanie tych metod jest istotne w klasach danych?

implementując te trzy metody tworzymy value objects, klasy, dla których dowolne dwie instancje o odpowiednio równych wartościach pól są uważane za wymienne. (Uwaga: aby była całkowicie prawdziwa, musimy uczynić klasę niezmienną. Dopełnienie pól i usunięcie seterów pomaga. Niezmienność jest często uważana za dobrą praktykę i zalecana, jeśli to możliwe)

  • equals() : domyślnie zwraca true tylko wtedy, gdy obie zmienne odnoszą się do tego samego obiektu, tzn. gdy pozycja w pamięci jest taka sama. Nadpisujemy tę metodę do zwracania true, jeśli obiekty zawierają te same informacje, innymi słowy, jeśli obiekty reprezentują ten sam podmiot. Sprawdza właściwości są takie same i zawierają tę samą wartość.
  • hashCode() : domyślnie zwraca adres pamięci obiektu w układzie szesnastkowym. Jest to wartość liczbowa służąca do identyfikacji obiektu podczas testowania równości, tzn. równe obiekty mają ten sam kod skrótu. Metoda ta musi zostać nadpisana, gdy toString() jest nadpisana, więc zwraca kod skrótu obliczony na podstawie wartości właściwości.
  • toString(): Domyślnie zwraca typ obiektu i hashCode(), na przykład [email protected]+. Nadpisujemy tę metodę, aby mieć bardziej czytelną dla człowieka wersję obiektu, taką jak User(name=Steve, surname=Jobs).

pomimo tego, że jest tak ważnym pojęciem, nie ma nic w powyższym kodzie Javy, co odróżniłoby tę klasę od innych. Programiści mogą rozpoznać ją jako klasę danych ze względu na strukturę klas i wzorce, ale z punktu widzenia kompilatora, ta klasa jest po prostu kolejną klasą.

Tworzenie klas danych jest tak powszechne, że programiści często używają IDE i innych wtyczek, aby pomóc im w tym powtarzalnym zadaniu. Ból tworzenia klasy danych w Javie może być złagodzony przez wtyczki lub IDE, ale większość błędów jest wprowadzana przy dalszych modyfikacjach tych klas. Bardzo łatwo jest zapomnieć o odpowiedniej modyfikacji wszystkich metod towarzyszących za każdym razem, gdy pole jest usuwane lub dodawane.

Klasa danych w Javie nie obsługuje języka. Jest to powtarzalne i podatne na błędy zadanie, które stanowi zbyt duże tarcie dla współczesnego języka programowania.

Klasa danych w Kotlinie

ta sama klasa danych w Kotlinie wyglądałaby mniej więcej tak:

data class User(var name: String, var age: Int)

Kotlin podnosi klasy danych do pierwszej klasy, wprowadzając słowo kluczowe data. Rozwalmy to.

  • Gettery i settery

gettery i settery są tworzone automatycznie w Kotlinie, gdy deklarujemy właściwości. W skrócie, co var name: String oznacza, że KlasaUser ma właściwość, która jest publiczna (domyślna widoczność w Kotlinie), zmienna (var) i jest typem String. Biorąc pod uwagę, że jest publiczny, tworzy getter, a biorąc pod uwagę, że jest zmienny, tworzy setter.

jeśli chcemy, aby klasa była tylko do odczytu (bez seterów), musimy użyć val :

data class User(val name: String, val age: Int)

możemy mieszać val i var w tej samej deklaracji klasy. Możesz myśleć o val jako o zmiennej final w Javie.

wszystko wyjaśnione do tej pory, jest wspólne dla każdej deklaracji klasy w Kotlinie, ale słowo kluczowe datajest tym, co robi różnicę.

  • słowo kluczowe data

deklarowanie klasy jako klasy danych spowoduje automatyczne zaimplementowanie toString(), hashCode() i equals() w ten sam sposób, w jaki opisaliśmy powyżej dla klasy Java. Więc jeśli utworzymy klasę user taką jak User("Steve Jobs",56) i wywołamy metodę toString(), otrzymamy coś w stylu:User(name=Steve Jobs, age=56).

deklaracje destrukcji

słowo kluczowe data udostępnia funkcje, które umożliwiają deklaracje destrukcji. Krótko mówiąc, tworzy funkcję dla każdej właściwości, więc możemy robić takie rzeczy:

funkcja Copy

słowo kluczowe data daje nam przydatny sposób kopiowania klas zmieniających wartość niektórych właściwości. Jeśli chcemy utworzyć kopię użytkownika zmieniającego wiek, zrobimy to w ten sposób:

właściwości zadeklarowane w ciele klasy są ignorowane

kompilator używa tylko właściwości zdefiniowanych wewnątrz głównego konstruktora dla automatycznie generowanych funkcji.

właściwość address nie będzie traktowana przez słowo kluczowe data, więc oznacza to, że automatycznie wygenerowane implementacje ją zignorują.

pary i potrójne

Pair i Triple są standardowymi klasami danych w bibliotece, ale sami Kotin Docs zniechęcają do ich używania na rzecz bardziej czytelnych i dostosowanych do indywidualnych potrzeb klas danych.

wymagania i ograniczenia

  • konstruktor klasy danych musi mieć co najmniej jeden parametr.
  • wszystkie parametry muszą być dostępne jako val lub var.
  • Klasa danych nie może być abstract, open, sealed lub inner
  • equals , toString i hashCode metody mogą być jawnie nadpisywane.
  • jawne implementacje funkcji componentN() i copy() nie są dozwolone.
  • Wyprowadzanie klasy danych z Typu o sygnaturze funkcji copy() było przestarzałe w Kotlinie 1.2 i zabronione w Kotlinie 1.3.
  • a data klasa nie może rozszerzyć się z innej klasy data.
  • a data klasa może rozszerzać inne klasy (od Kotlina 1.1)

Klasy danych są pierwszorzędnymi obywatelami w Kotlinie. W bardzo krótkiej składni oferują bezproblemowe rozwiązanie ze wszystkimi zaletami i bez kompromisów.

co to znaczy dla Androida

spróbuję wyjaśnić, jakie są główne zalety, które znalazłem przy użyciu klas danych Kotlin w moich projektach na Androida. To nie wszystkie i może nie te najważniejsze, ale te są najbardziej oczywiste z mojego dotychczasowego doświadczenia.

  • Modele danych

Architektura w Androidzie była (i nadal jest) gorącym tematem. Istnieje wiele opcji, ale większość z nich łączy oddzielenie obaw i zasady jednolitej odpowiedzialności. Czysta Architektura-bardzo znana w społeczności Androida – to zestaw dobrych praktyk, których należy przestrzegać, dążąc do dobrej architektury, która kładzie nacisk na używanie różnych modeli dla różnych warstw architektury. Oznacza to, że projekt z 3 lub 4 różnymi modelami danych staje się standardem.

oznacza to, że liczba klas danych w projekcie jest bardzo wysoka, a operacje takie jak tworzenie, odczyt, modyfikowanie, kopiowanie, porównywanie, mapowanie… klasy modeli danych są codziennymi zadaniami, które korzystają z automatycznie generowanego kodu Klasy danych Kotin. Oszczędza ogromną ilość czasu i zmniejsza możliwości wprowadzania błędów.

  • koniec z automatyczną wartością

używanie typów wartości jest dobrą praktyką bardzo rozszerzoną w Androidzie, szczególnie wśród klas danych.

typ wartości jest obiektem z niezmiennej klasy wartości.
Klasa wartości to klasa, dla której równość zależy od jej zawartości.
Klasa niezmienna to klasa, której nie można modyfikować po utworzeniu.

AutoValue to popularna biblioteka Google, która pomaga nam tworzyć typy wartości. Robi swoje, ale jest bardzo gadatliwy na coś, co nie powinno być tak skomplikowane.

używanie klas kotlin data z modyfikatorem dostępu val daje nam wystarczająco zbliżone przybliżenie do typów wartości.

data class User(val name : String, val age : Int)

poprzednia klasa User jest klasą wystarczająco zbliżoną do typów wartości, w znacznie krótszej składni. Dla dobrej grupy ludzi AutoValue można zastąpić Kotlinem. Mniej kodu, brak przetwarzania adnotacji i o jedną bibliotekę mniej.

Uwaga: Kotlin oferuje właściwości i klasy tylko do odczytu ze słowem kluczowym val. Tylko do odczytu i niezmienny nie jest taki sam (więcej tutaj), ale ogólnie jest uważany za wystarczająco dobry do celów praktycznych.

  • koniec Lombok

jednym ze sposobów, w jaki programiści starali się oszczędzać czas podczas pracy z klasami danych, jest użycie bibliotek do generowania metod getter i setter. Lombok jest jednym z (w)słynnych W Android / Java. Wymaga nie tylko biblioteki, ale także wtyczki do AS. Krótko mówiąc, dla większości programistów Lombok przynosi tyle korzyści, co bóle głowy, więc staje się to biblioteka, którą zaczynasz kochać, ale po pewnym czasie nie możesz się doczekać, aby się jej pozbyć, ale nigdy nie robisz, ponieważ jest wszędzie.

biorąc pod uwagę, że Klasy danych Kotlina nie wymagają ręcznego zapisu metod getter/setter, główna potrzeba dla Lombok zniknęła.

  • RecyclerView DiffUtil

RecyclerView w Androidzie jest widżetem. Jest w każdej aplikacji na wielu ekranach. Ważnym elementem podczas wdrażania adapterów RecyclerView jest klasa DiffUtil. DiffUtil oblicza różnicę między dwoma listami w celu wysłania zmian-jeśli występują-do adaptera. Jest o wiele bardziej wydajny niż odświeżanie całej listy w kółko i pięknie animuje zmiany.

DiffUtil opiera się głównie na równości elementów, co oznacza, że dwa elementy są takie same, gdy ich zawartość jest taka sama. Za każdym razem, gdy używasz RecyclerView, powinieneś używać DiffUtil, co oznacza, że potrzebujesz sposobu porównywania, czy dwa obiekty zawierają te same informacje. Jest to jeden z powodów, dla których musimy nadpisać equals w naszych klasach danych Java, ale z klasami Kotlin data jest to bezpłatne.

Uwaga: Jeśli nie jesteś zaznajomiony z Diffutilem, sprawdź ten krótki przewodnik.

  • testy

w klasach testowych stale sprawdzamy, czy oczekiwane wartości są zgodne z rzeczywistymi wartościami. Porównywanie równości obiektów (jak opisano wcześniej) jest bardzo częstym zadaniem.

nawet jeśli nie musisz nadpisywać tripletów equals , toString i toHash dla zwykłego środowiska uruchomieniowego aplikacji, szanse, że będziesz musiał nadpisać te metody do celów testowych są wysokie, więc Klasy danych Kotlin wyczyszczą ścieżkę do testowania bez wymówek.

dodatek

porozmawiajmy o innych typowych scenariuszach, o których warto wspomnieć podczas pracy z klasami danych Kotlina. Nie jest to ściśle związane z klasami danych, ale są one szczególnie powszechne wśród nich.

  • wiele konstruktorów
data class User(val name : String, val age : Int)

w klasie User zdefiniowanej wcześniej, musimy jawnie określić name i age podczas tworzenia instancji takiej jak User("Steve", 56) .

w Kotlinie możemy zdefiniować domyślne wartości dla argumentów w taki sposób, że w przypadku, gdy nie przekażemy wartości dla tego argumentu, zostanie do niego przypisana wartość domyślna.

data class User(val name : String, val age :Int = 0)

User("Steve", 56) jest nadal poprawny, ale teraz dozwolony jest drugi konstruktor User("Steve"). W takim przypadku wartość age będzie równa 0.

możemy przypisać wartości domyślne do obu parametrów, pozwalając na trzeci konstruktor User() gdzie name będzie pusty, a age będzie 0.

data class User(val name : String = "", val age : Int = 0)

więc teraz User(), User("Steve") i User("Steve",56) wszystkie są poprawnymi połączeniami.

ma to pewne ograniczenia: opcjonalne parametry muszą być ostatnimi parametrami w konstruktorze. Następny nie będzie się kompilował.

data class User(val name : String = "", val age : Int)
val user = User(56) // This doesn't compile

kolejnym ograniczeniem jest to, że jeśli mamy wiele opcjonalnych parametrów, muszą one zostać pominięte od prawej do lewej.

data class User(
val name : String,
val surname : String = "",
val age : Int = 0
)User("Steve")
User("Steve", "Jobs")
User("Steve", "Jobs", 56)
User("Steve",56) // This wont compile

aby poradzić sobie z tymi ograniczeniami, Kotlin oferuje nazwane argumenty. Pozwala nam to określić, do którego argumentu należy każda wartość. Teraz możemy zrobić takie rzeczy jakUser(„Steve”, age = 56) – gdzie nazwa zostanie przypisana do wartości domyślnej.

argumenty domyślne i argumenty nazwane są bardzo poręcznym sposobem oferowania wielu konstruktorów i przeciążeń z bardzo zwartej deklaracji.

  • @JvmOverloads

wszystko wyjaśnione w poprzednim punkcie nie bierze pod uwagę wywołań od strony Javy. Kotlin jest kompatybilny z Javą, więc musimy być w stanie tworzyć instancje klasy User z Javy.

jeśli nie zamierzasz używać go z Javy, to gotowe, ale w przeciwnym razie będziesz potrzebował adnotacji @JvmOverloads, biorąc pod uwagę, że Java nie oferuje nazwanych argumentów.

data class User @JvmOverloads constructor(
val name : String,
val surname : String = "",
val age : Int = 0
)

co to robi generując wiele konstruktorów, dzięki czemu można go wywołać z Javy.

Uwaga: ważne jest, aby zauważyć, że nie stworzy to każdej możliwej permutacji, ale tych wynikających z usunięcia opcjonalnych argumentów z prawej do lewej. Więcej tutaj

  • Builders

biorąc pod uwagę, że Kotlin oferuje nazwane parametry i domyślne argumenty, sprawia to, że mniej prawdopodobne jest zapotrzebowanie na builders. Ponadto nowoczesne IDE, takie jak Android Studio, pokazują już nazwę parametru po stronie wywołania, co ułatwia czytanie, co czyni go mniej interesującym tylko dla celów czytelności.

w przypadkach, gdy wzór budowniczego jest nadal potrzebny. Kotlin nie oferuje nic specjalnego, aby nam w tym pomóc. Wzorzec budowniczy w Kotlinie wygląda jak:

  • adnotacje

bardzo często niektóre klasy modeli danych używają przetwarzania adnotacji. Na przykład modele API (klasy danych reprezentujące zderializowane odpowiedzi z API) są często adnotowane adnotacjami Gson lub Moshi. Modele trwałości (klasy danych do reprezentowania danych przechowywanych w lokalnej pamięci masowej/bazach danych)są często adnotowane za pomocą adnotacji pokoju lub obszaru.

w Kotlinie nadal możemy używać tych adnotacji. Na przykład jest to model użytkownika, który ma być przechowywany w bazie danych pokoju:

podsumowanie

Kotlin klasy danych są wynikiem lat uczenia się od bólu i frustracji z klas danych w Javie. Mają na celu posiadanie wszystkich zalet i żadnych wad. Korzystanie z nich jest bardzo proste i przyjemne, a kiedy już się do tego przyzwyczaisz, bardzo trudno jest spojrzeć wstecz.

w Androidzie pomagają nam na różne sposoby, ale przede wszystkim oszczędzają dużo czasu i redukują błędy.

Klasa danych Kotlina jest dobrym przykładem tego, czym jest Kotlin jako język programowania: zwięzły, pragmatyczny i radosny dla programistów.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.

lg