Delegált ingatlanok Kotlinban

1. Bemutatkozás

A Kotlin programozási nyelv natív támogatást nyújt az osztály tulajdonságaihoz.

A tulajdonságokat általában közvetlenül a megfelelő mezők támogatják, de ennek nem mindig kell így lennie - mindaddig, amíg megfelelő módon vannak kitéve a külvilágnak, tulajdonságoknak tekinthetők.

Ezt úgy lehet elérni, hogy ezt kezelőkben és beállítókban kezeljük, vagy a Küldöttek.

2. Melyek a delegált tulajdonságok?

Egyszerűen fogalmazva, a delegált tulajdonságokat nem támogatja egy osztály mező, és a delegálást és beállítást egy másik kódrészre delegálják. Ez lehetővé teszi a delegált funkcionalitás kivonását és megosztását több hasonló tulajdonság között - pl. tulajdonságértékek tárolása a térképen külön mezők helyett.

A delegált tulajdonságokat a tulajdonság és az általa használt megbízott deklarálásával használják. A által kulcsszó azt jelzi, hogy a tulajdonságot a megadott küldött ellenőrzi a saját mezője helyett.

Például:

class DelegateExample (térkép: MutableMap) {var name: String by map}

Ez azt a tényt használja, hogy a MutableMap maga is egy megbízott, amely lehetővé teszi, hogy kulcsait tulajdonságként kezelje.

3. Standard delegált tulajdonságok

A Kotlin standard könyvtár egy sor standard küldöttet tartalmaz, amelyek készen állnak a használatra.

Már láttunk egy példát az a használatára MutableMap hogy megváltoztatható tulajdonságot támogasson. Ugyanígy visszaállíthat egy megváltoztathatatlan tulajdonságot az a használatával Térkép - lehetővé teszi az egyes mezők tulajdonságokként való elérését, de soha nem változtatja meg őket.

A lusta A delegate lehetővé teszi egy tulajdonság értékének kiszámítását csak az első hozzáféréskor, majd a gyorsítótárban. Ez hasznos lehet azoknál a tulajdonságoknál, amelyek kiszámítása költséges lehet, és amelyekre soha nem lesz szüksége - például adatbázisból töltve:

class DatabaseBackedUser (userId: String) {val név: String by lazy {queryForValue ("SELECT name FROM users WHERE userId =: userId", mapOf ("userId" to userId)}}

A megfigyelhető A delegate lehetővé teszi a lambda aktiválását, amikor a tulajdonság értéke megváltozik, például a változásértesítések engedélyezése vagy más kapcsolódó tulajdonságok frissítése:

class ObservedProperty {var name: String by Delegates.observable ("") {prop, old, new -> println ("Régi érték: $ régi, Új érték: $ új")}}

A Kotlin 1.4-től kezdődően lehetőség van közvetlenül egy másik ingatlanra is átruházni. Például, ha egy tulajdonságot átnevezünk egy API osztályba, akkor hagyhatjuk a régit a helyén, és egyszerűen átruházhatjuk az újra:

class RenamedProperty {var newName: String = "" @Deprecated ("NewName use helyett") var name: String by this :: newName}

Itt bármikor elérhetjük a név tulajdon, akkor hatékonyan használjuk a új név tulajdon helyett.

4. A küldöttek létrehozása

Időnként meg akarja írni a küldötteket, ahelyett, hogy a már létezőket használja. Ez egy olyan osztály megírásán alapul, amely kiterjeszti a két felület egyikét - ReadOnlyProperty vagy ReadWriteProperty.

Mindkét interfész meghatározza az úgynevezett módszert getValue - amely a delegált tulajdonság aktuális értékének megadására szolgál, amikor elolvassa. Ehhez két argumentumra van szükség, és visszaadja a tulajdonság értékét:

  • thisRef - hivatkozás arra az osztályra, amelybe az ingatlan tartozik
  • ingatlan - a delegált ingatlan reflexiós leírása

A ReadWriteProperty interfész ezen felül meghatározza az úgynevezett metódust érték beállítása amely a tulajdonság aktuális értékének frissítésére szolgál, amikor az meg van írva. Ehhez három argumentum szükséges, és nincs visszatérési értéke:

  • thisRef - Hivatkozás arra az osztályra, amelybe az ingatlan tartozik
  • ingatlan - A delegált ingatlan reflexiós leírása
  • érték - Az ingatlan új értéke

A Kotlin 1.4-től kezdődően a ReadWriteProperty interfész valójában kiterjed ReadOnlyProperty. Ez lehetővé teszi számunkra, hogy egyetlen küldött osztályt írjunk meg ReadWriteProperty és csak olvasható mezőkhöz használjuk a kódunkban. Korábban két különböző megbízottat kellett volna írnunk - az egyiket csak olvasható mezőkhöz, a másikat pedig változtatható mezőkhöz.

Példaként írjunk egy megbízottat, amely mindig az adatbázis-kapcsolattal kapcsolatban működik, a helyi mezők helyett:

class DatabaseDelegate (readQuery: String, writeQuery: String, id: Any): ReadWriteDelegate {fun getValue (thisRef: R, tulajdonság: KProperty): T {return queryForValue (readQuery, mapOf ("id" - id))} fun setValue ( thisRef: R, tulajdonság: KProperty, érték: T) {frissítés (writeQuery, mapOf ("id" idre, "érték" értékre)}}}

Ez két legfelső szintű függvénytől függ az adatbázis eléréséhez:

  • queryForValue - Ehhez némi SQL szükséges, néhány pedig köt és visszaadja az első értéket
  • frissítés - Ehhez némi SQL szükséges, más része pedig UPDATE utasításként kezeli és kezeli

Ezután ezt használhatjuk, mint bármelyik rendes küldöttet, és az osztályunkat automatikusan az adatbázis támogatja:

class DatabaseUser (userId: String) {var name: String by DatabaseDelegate ("SELECT name FROM users WHERE userId =: id", "UPDATE users SET name =: value WHERE userId =: id", userId) var email: String by DatabaseDelegate ("E-mail kiválasztása a felhasználóktól WHERE userId =: id", "UPDATE users SET email =: value WHERE userId =: id", userId)}

5. Delegált alkotás delegálása

A Kotlin 1.4-ben egy másik újdonság, hogy delegált osztályaink létrehozását átruházhatjuk egy másik osztályra. Ez a program végrehajtásával működik PropertyDelegateProvider interfész, amelynek egyetlen módszere van a tényleges megbízottként használandó dolgok példányosítására.

Ezt használhatjuk néhány kód végrehajtására a használni kívánt megbízott létrehozása körül - például naplózhatjuk a történteket. Használhatjuk arra is, hogy dinamikusan kiválasszuk azt a küldöttet, amelyet használni fogunk, az általa használt tulajdonság alapján. Például más delegáltunk lehet, ha a tulajdonság érvénytelen:

osztály DatabaseDelegateProvider(readQuery: String, writeQuery: String, id: Any): PropertyDelegateProvider {felülbírálja az operátor szórakoztató ProviderDelegate (thisRef: T, prop: KProperty): ReadWriteDelegate {if (prop.returnType.isMarkedNullable) {return NullableDatabaseDelegate (readQuery, writeQuery, id)} else {return NonNullDatabaseDelegate} readQu

Ez lehetővé teszi számunkra, hogy egyszerűbb kódot írjunk minden küldöttbe, mert nekik csak célzottabb esetekre kell koncentrálniuk. A fentiekben ezt tudjuk NonNullDatabaseDelegate csak olyan tulajdonságokon fogják használni, amelyek nem rendelkeznek a nulla értéket, ezért nincs szükségünk különösebb logikára ennek kezeléséhez.

6. Összefoglalás

A tulajdon delegálása egy hatékony technika, amely lehetővé teszi olyan kód megírását, amely átveszi a többi tulajdonság ellenőrzését, és elősegíti a logika egyszerű megosztását a különböző osztályok között. Ez lehetővé teszi a robusztus, újrafelhasználható logikát, amely úgy néz ki és úgy néz ki, mint a rendszeres ingatlan-hozzáférés.

Ennek a cikknek egy teljesen működő példája megtalálható a GitHub oldalon.