o clasă de date este un concept care nu este legat de niciun limbaj de programare specific, este un model suficient de convenabil pentru majoritatea programatorilor ca o modalitate simplă de a reprezenta, încapsula și muta informații.

o clasă de date se referă la o clasă care conține numai câmpuri și metode brute pentru accesarea acestora (getters și setters). Acestea sunt pur și simplu containere pentru datele utilizate de alte clase. Aceste clase nu conțin nicio funcționalitate suplimentară și nu pot funcționa independent pe datele pe care le dețin.

de obicei, clasele de date reprezintă entități din lumea reală și este obișnuit să ai zeci sau sute de astfel de clase într-un proiect, ceea ce înseamnă că crearea, modificarea și manipularea acestor obiecte este o sarcină foarte comună pentru un dezvoltator.

o clasă de date în Java

acesta este modul în care o clasă de date arată de obicei în Java:

veți observa că înlocuim metodele toString(), equals() și hashCode() (declarate în clasa Object.java). De ce este relevantă suprascrierea acestor metode în clasele de date?

când implementăm aceste trei metode, creăm obiecte de valoare, clase pentru care oricare două instanțe cu valori de câmp corespunzător egale sunt considerate interschimbabile. (Notă: pentru a fi complet adevărat, va trebui să facem clasa imuabilă. Efectuarea câmpurilor finale și eliminarea setterilor ajută. Imutabilitatea este adesea considerată o bună practică și recomandată atunci când este posibil)

  • equals() : în mod implicit, returnează true doar dacă cele două variabile se referă la același obiect, adică dacă poziția în memorie este aceeași. Suprascriem această metodă pentru returnarea true dacă obiectele conțin aceleași informații, cu alte cuvinte, dacă obiectele reprezintă aceeași entitate. Se verifică proprietățile sunt aceleași și conțin aceeași valoare.
  • hashCode() : în mod implicit, returnează adresa de memorie a obiectului în hexazecimal. Este o valoare numerică pentru a identifica un obiect în timpul testării egalității, adică obiectele egale au același cod hash. Această metodă trebuie suprascrisă atunci când toString() este suprascrisă, astfel încât returnează un cod hash calculat din valorile proprietăților.
  • toString(): În mod implicit returnează tipul de obiect și hashCode(), de exemplu [email protected]+ . Suprascriem această metodă pentru a avea o versiune mai ușor de citit de om a obiectului, cum ar fi User(name=Steve, surname=Jobs) .

în ciuda faptului că este un concept atât de important, nu există nimic în codul Java de mai sus care să facă această clasă diferită de oricare alta. Programatorii o pot recunoaște ca o clasă de date datorită structurii și modelelor clasei, dar din punct de vedere al compilatorului, această clasă este doar o altă clasă.

crearea claselor de date este atât de comună încât dezvoltatorii folosesc adesea IDE și alte pluginuri pentru a-i ajuta cu această sarcină repetitivă. Durerea de a crea o clasă de date în Java poate fi atenuată de plugin-uri sau IDE, dar cele mai multe bug-uri sunt introduse pe alte modificări ale acestor clase. Este foarte ușor să uitați să modificați toate metodele însoțitoare în consecință de fiecare dată când un câmp este eliminat sau adăugat.

o clasă de date în Java nu are suport lingvistic. Este o sarcină repetitivă și predispusă la erori, care reprezintă prea multă frecare pentru un limbaj de programare modern.

o clasă de date în Kotlin

aceeași clasă de date în Kotlin ar arata ceva de genul asta:

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

Kotlin ridică clasele de date pentru cetățenii de primă clasă care introduc cuvântul cheie data. Să-l rupe în jos.

  • Getters și setters

getters și setters sunt create automat în Kotlin atunci când declarăm proprietăți. Pe scurt, ceea ce înseamnă var name: String este că clasa User are o proprietate publică (vizibilitate implicită în Kotlin), mutabilă (var) și este un tip String. Având în vedere că este publică creează getter, și având în vedere că este mutabil creează setter.

dacă vrem să facem clasa read-only (fără setteri), trebuie să folosim val :

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

putem amesteca val și var în aceeași declarație de clasă. Vă puteți gândi la val ca la o variabilă final în Java.

totul explicat până acum, este comun oricărei declarații de clasă din Kotlin, dar cuvântul cheie data este ceea ce face diferența aici.

  • cuvântul cheie data

declararea unei clase ca clasă de date ne va pune în aplicare toString(), hashCode() și equals() automat în același mod descris mai sus pentru clasa Java. Deci, dacă vom crea o clasă de utilizator ca User("Steve Jobs",56) și apel toString() metoda vom obține ceva de genul:User(name=Steve Jobs, age=56) .

Declarații de distrugere

cuvântul cheie data oferă funcții care permit declarații de distrugere. Pe scurt, creează o funcție pentru fiecare proprietate, astfel încât să putem face lucruri de genul acesta:

funcția de copiere

cuvântul cheie data ne oferă o modalitate utilă de copiere a claselor care modifică valoarea unor proprietăți. Dacă dorim să creăm o copie a unui utilizator care schimbă vârsta, acesta este modul în care am face-o:

proprietățile declarate în corpul clasei sunt ignorate

compilatorul utilizează numai proprietățile definite în interiorul constructorului primar pentru funcțiile generate automat.

proprietatea address nu va fi tratată de cuvântul cheie data, deci înseamnă că implementările generate automat îl vor ignora.

Pair și Triple

Pair și Triple sunt clase de date standard în bibliotecă, dar documentele Kotin descurajează utilizarea acestora în favoarea unor clase de date mai lizibile și personalizate.

cerințe și limitări

  • un constructor de clase de date trebuie să aibă cel puțin un parametru.
  • toți parametrii trebuie să fie de piață ca val sau var.
  • o clasă de date nu poate fi abstract, open, sealed sau inner.
  • equals , toString și hashCode metodele pot fi suprascrise în mod explicit.
  • implementări explicite pentru componentN() și copy() funcții nu sunt permise.
  • derivarea unei clase de date dintr-un tip cu o semnătură de potrivire a funcției copy() a fost depreciată în Kotlin 1.2 și a fost interzisă în Kotlin 1.3.
  • o clasă data nu se poate extinde de la o altă clasă data.
  • a data clasa poate extinde alte clase (de la Kotlin 1.1)

clasele de date sunt cetățeni de primă clasă în Kotlin. Într-o sintaxă foarte scurtă, acestea oferă o soluție fără frecare, cu toate avantajele și fără compromisuri.

ce înseamnă pentru Android

voi încerca să explic care sunt principalele avantaje pe care le-am găsit folosind clasele de date Kotlin în proiectele mele Android. Acestea nu sunt toate și s-ar putea să nu fie cele mai importante, dar acestea sunt cele mai evidente din experiența mea de până acum.

  • modele de date

arhitectura în Android a fost (și încă este) un subiect fierbinte. Există mai multe opțiuni, dar cele mai multe dintre ele au în comun separarea preocupărilor și principiile unice de responsabilitate. Arhitectura curată – foarte renumită în comunitatea Android-este un set de bune practici de urmat atunci când vizează o arhitectură bună care pune accentul pe utilizarea diferitelor modele pentru diferite straturi ale arhitecturii. Aceasta înseamnă că un proiect cu 3 sau 4 modele de date diferite devin standard.

asta înseamnă că numărul de clase de date dintr-un proiect este foarte mare, iar operațiuni precum crearea, citirea, modificarea, copierea, Compararea, harta… clasele de modele de date sunt sarcini zilnice care beneficiază de codul generat automat de clasa de date Kotin. Economisește o cantitate imensă de timp și reduce oportunitățile de introducere a erorilor.

  • nu mai Auto-valoare

utilizarea tipuri de valori este o bună practică foarte extins în Android, în special în rândul claselor de date.

un tip de valoare este un obiect dintr-o clasă de valoare imuabilă.
o clasă de valoare este o clasă pentru care egalitatea depinde de conținutul său.
o clasă imuabilă este o clasă care nu poate fi modificată după creație.

AutoValue este o bibliotecă populară de la Google care ne ajută să creăm tipuri de valori. Își face treaba, dar este foarte detaliat pentru ceva care nu ar trebui să fie atât de complicat.

utilizarea claselor kotlin data cu modificatorul de acces val ne oferă o aproximare suficient de apropiată de tipurile de valori.

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

clasa utilizator anterioară este o clasă suficient de apropiată de tipurile de valori, într-o sintaxă mult mai scurtă. Pentru o bucată bună de oameni, AutoValue poate fi înlocuit de Kotlin. Cod mai puțin, nici o prelucrare adnotare, și o bibliotecă mai puțin să depindă de.

notă: Kotlin oferă read-only proprietăți și clase cu val cuvânt cheie. Read-only și imuabil nu este același lucru (mai mult aici), dar, în general, este considerat suficient de bun pentru scopuri practice.

  • nu mai Lombok

unul dintre modurile în care dezvoltatorii au încercat să economisească timp atunci când se ocupă de clase de date este utilizarea bibliotecilor pentru a genera metode getter și setter. Lombok este unul dintre (în)cele celebre în Android/Java. Este nevoie nu numai biblioteca, ci și un plugin pentru AS. Povestea pe scurt este pentru majoritatea dezvoltatorilor Lombok aduce cât mai multe avantaje ca dureri de cap, astfel încât devine că biblioteca începe iubitoare, dar după un timp, nu se poate aștepta pentru a scăpa de, dar nu faci pentru că este peste tot.

având în vedere că clasele de date Kotlin nu necesită scrierea manuală a metodelor getter/setter, nevoia principală de Lombok a dispărut.

  • RecyclerView DiffUtil

RecyclerView în Android este widget-ul. Este în fiecare aplicație în mai multe ecrane. O componentă importantă la implementarea adaptoarelor RecyclerView este clasa DiffUtil. DiffUtil calculează diferența dintre două liste pentru a trimite modificările-dacă există – la adaptor. Este mult mai eficient decât reîmprospătarea întregii liste din nou și din nou și animă schimbările frumos.

DiffUtil se bazează foarte mult pe egalitatea elementelor, ceea ce înseamnă că două elemente sunt aceleași atunci când conținutul lor este același. De fiecare dată când utilizați un RecyclerView, ar trebui să utilizați DiffUtil, ceea ce înseamnă că aveți nevoie de o modalitate de a compara dacă două obiecte conțin aceleași informații. Acesta este unul dintre motivele pentru care trebuie să suprascriem equals în clasele noastre de date Java, dar cu clasele Kotlin data vine gratuit.

Notă: Dacă nu sunteți familiarizat cu DiffUtil, verificați acest ghid de pornire rapidă.

  • teste

în clasele de testare, verificăm constant dacă valorile așteptate se potrivesc cu valorile reale. Compararea egalității obiectelor (așa cum este descris anterior) este o sarcină foarte frecventă.

chiar dacă nu aveți nevoie pentru a suprascrie equals, toString și toHash triplet pentru tine runtime App regulat, șansele pe care le va trebui să suprascrie aceste metode în scopuri de testare sunt mari, astfel încât clasele de date Kotlin clar calea spre testare fără scuze.

Addendum

să vorbim despre alte scenarii comune care merită menționate atunci când lucrați cu clasele de date Kotlin. Acest lucru nu este strict legat de clasele de date, dar sunt deosebit de frecvente printre ele.

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

în clasa User pe care am definit-o anterior, trebuie să specificăm în mod explicit name și age atunci când creăm o instanță precum User("Steve", 56).

în Kotlin putem defini valorile implicite pentru argumente în așa fel încât, în cazul în care nu trecem o valoare pentru acel argument, valoarea implicită îi este atribuită.

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

User("Steve", 56) este încă valabil, dar acum este permis un al doilea constructor User("Steve"). În acest caz, valoarea age va fi 0.

putem atribui valori implicite ambilor parametri permițând unui al treilea constructor User() unde name va fi gol și age va fi 0.

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

Deci, acum User(), User("Steve") și User("Steve",56) toate sunt apeluri valide.

acest lucru are unele limitări: parametrii Optionali trebuie să fie ultimii parametri în constructor. Următorul nu va compila.

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

o altă limitare este că, dacă avem mai mulți parametri opționali, aceștia trebuie săriți de la dreapta la stânga.

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

pentru a face față acestor limitări Kotlin oferă argumente numite. Acest lucru ne permite să specificăm cărui argument aparține fiecărei valori. Acum putem face lucruri precumUser(name = "Steve", age = 56) — sau mai scurt User("Steve", age = 56) — unde numele de familie va fi atribuit valorii implicite.

argumentele implicite și argumentele numite sunt o modalitate foarte utilă de a oferi mai mulți constructori și supraîncărcări dintr-o declarație foarte compactă.

  • @JvmOverloads

toate explicate în punctul anterior nu iau în considerare apelurile din partea Java. Kotlin este interoperabil cu Java, deci trebuie să putem crea instanțe ale clasei User din Java.

dacă nu o veți folosi din Java, atunci ați terminat, dar altfel, veți avea nevoie de adnotarea @JvmOverloads, având în vedere că Java nu oferă argumente numite.

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

ce face acest lucru generând mai mulți constructori, astfel încât să poată fi apelat din Java.

Notă: este important să observați că nu va crea toate permutările posibile, ci cele care rezultă din eliminarea argumentelor opționale de la dreapta la stânga. Mai multe aici

  • Constructori

având în vedere Kotlin oferă parametri numiți și argumente implicite, face mai puțin probabil nevoia de constructori. În plus, IDE-urile moderne precum Android Studio arată deja numele parametrului pe partea de apelare, facilitând citirea, făcându-l mai puțin interesant doar în scopuri de lizibilitate.

în cazurile în care modelul constructor este încă necesar. Kotlin nu oferă nimic special care să ne ajute cu asta. Un model de constructor în Kotlin arată ca:

  • adnotări

este foarte frecvent ca unele clase de modele de date să utilizeze procesarea adnotărilor. De exemplu, modelele API (clase de date pentru a reprezenta răspunsuri deserializate din API) sunt adesea adnotate cu adnotări Gson sau Moshi. Modelele de persistență (clase de date pentru a reprezenta datele stocate în stocarea/bazele de date locale) sunt adesea adnotate cu adnotări de cameră sau de tărâm.

în Kotlin putem folosi în continuare aceste adnotări. De exemplu, acesta este un model de utilizator care trebuie stocat în baza de date a camerei:

rezumat

clasele de date Kotlin sunt rezultatul anilor de învățare din durere și frustrare cu clasele de date din Java. Ei urmăresc să aibă toate avantajele și niciunul dintre dezavantaje. Folosirea lor este foarte simplă și plăcută și, odată ce te obișnuiești, este foarte dificil să te uiți înapoi.

în Android, ne ajută în moduri diferite, dar mai ales economisesc mult timp și reduc Erorile.

o clasă de date Kotlin este un bun exemplu a ceea ce Kotlin este ca limbaj de programare: concis, pragmatic și o bucurie pentru dezvoltatori.

Lasă un răspuns

Adresa ta de email nu va fi publicată.

lg