Vzorec oblikovanja skladišča v Swiftu

Čist način poizvedovanja po svojih modelih

Kateri problem rešuje?

Če morate znova in znova poizvedovati predloge svojih modelov z različnih lokacij v kodi, je lahko resnično koristno skladišče, ki vam bo omogočilo eno vhodno točko za delo z vašimi modeli in odstranjevanje podvojenih poizvedbenih kod. Lahko ga vzamete še dlje in ga uporabljate s protokoli, na ta način lahko preprosto izklopite izvedbe (na primer za enotne teste) ali pa jih uporabite z generiko, da naredite bolj * boben roll * generično abstrakcijo. V tem članku bom zajel vse te primere.

Skiciranje prizora.

Recimo, da imate neko kodo, ki pridobi podatke iz API-ja in jih preslika v modele objektov. V tem primeru bom dobil seznam člankov s strežnika.

To se morda zdi malce smešno, vendar je samo RxSwift, ki Moya uporablja kot sloj odvzema omrežja, vendar to v resnici ni pomembno, da bi razumeli, kaj se dogaja. Način, kako pridobite svoje podatke, je popolnoma odvisen od vas.

Ta del kode ima

  1. GET zahteva do strežnika
  2. Mape vrne JSON v niz predmetov Article
  3. Zaprtje se pokliče, ko je opravljeno vse delo.

Zakaj potrebujemo skladišče?

V tem trenutku še nimamo. Če API pokličete samo enkrat v celotni bazi kode, je lahko dodajanje skladišča prekomerno (ali kot nekateri pravijo prekomerni inženiring).

V redu ... ampak kdaj je objekt repozitorija primeren za uporabo?
Recimo, da se vaša koda začne povečevati in morate napisati kodo, da lahko članke prenašate znova in znova. Lahko bi rekli, "kopirajte kodo in jo prilepite kamor koli, da pridobite vse članke."

Brez storjene škode, nihče ni umrl. Prav?

V tistem trenutku bi vam v možganih začel utripati velik rdeč alarm.

Pozdravljeni repozitorij.

Repozitorij je samo predmet, ki zaklene vso kodo, da poizveduje vaše modele na enem mestu, tako da imate vnos z eno točko, če želite npr. dobili vse članke.

Ustvarimo predmet repozitorija, ki zagotavlja javni API za pridobivanje člankov.

Zdaj lahko to metodo imenujemo in ni nam treba skrbeti, kaj se dogaja v ozadju, da bi dobili dejanske članke.
Samo pokličite metodo in prejeli boste članke. Lepo, kajne?
Toda počakaj, obstaja še več!

Obravnavajte vse interakcije v članku

S skladiščem lahko dodamo več metod za interakcijo z našim objektnim modelom. Večina primerov želite narediti CRUD (ustvariti, prebrati, posodobiti, izbrisati) operacije na vašem modelu. No, samo dodajte logiko za te operacije v skladišču.

Tako je lep API, ki ga lahko uporabljate v celotni kodi, ne da bi morali isto kodo ponavljati znova in znova.

V praksi bi uporaba skladišča izgledala tako.

Precej lepo in berljivo, kajne? Ampak, počakajte, da postane še bolje.

Power-up: protokoli

V prejšnji kodi sem vedno uporabljal primer "pridobivanja podatkov iz API-ja". Kaj pa, če morate dodati podporo za nalaganje podatkov iz lokalne datoteke JSON namesto iz spletnega vira.

No, če ustvarite protokol, v katerem so navedena imena metod, lahko ustvarite izvedbo spletnega API-ja in enega, s katerim boste podatke brez povezave.

To bi lahko izgledalo takole.

V protokolu piše: "Če me spoštujete, morate imeti te podpise metod, vendar me ne zanima dejansko izvajanje!"

To je super, lahko ustvarite WebArticleRepository in LocalArticleRepository. Oba bosta imela vse metode, ki so navedene v protokolu, vendar lahko napišete 2 popolnoma različni izvedbi.

Power-up: Preizkušanje enot

Uporaba protokolov je zelo primerna tudi, če želite enotno preizkusiti svojo kodo, saj lahko samo ustvarite drug objekt, ki izvaja protokol repozitorija, namesto tega pa vrne posnemajoče podatke.

Če to uporabljate skupaj z injekcijo odvisnosti, je resnično preprosto preizkusiti določen predmet.

Primer

Recimo, da imate model ogledov, model pogleda pa svoje podatke pridobi v skladišču.

Če želite preizkusiti model pogleda, vas čakajo članki, ki jih boste lahko prenesli s spleta.
To pravzaprav ni tisto, kar si želimo. Želimo, da bi bil naš test čim bolj determinističen. V tem primeru se lahko članki, pridobljeni s spleta, sčasoma spremenijo, internetna povezava ne more biti v času, ko se preizkusi izvajajo, strežnik bi lahko padel,… to so vsi možni scenariji, v katerih naši testi ne bi uspeli, ker so izven našega nadzora. In ko testiramo, želimo / moramo imeti nadzor.

Na srečo je to resnično enostavno rešiti.

Pozdravljeni, injekcija odvisnosti.

Preprosto morate določiti lastnost ArticleRepo prek inicializatorja. Privzeti primer bo tisti, ki ga želite za svojo proizvodno kodo in ko napišete preizkus enote, lahko zamenjate skladišče z različico.

Mogoče pa razmišljate, kaj pa tipi? WebArticleRepository ni MockArticleRepository, zato se prevajalnik ne bo pritožil? No, ne, če protokol uporabljate kot vrsto. Na ta način obvestimo prevajalnika in omogočimo vse, če je v skladu s protokolom ArticleRepository (kar počneta tako splet kot MockArticleRepository).

Končna koda bi izgledala tako.

In v preizkusu svoje enote bi ga lahko zamenjali takole.

Zdaj imate popoln nadzor nad tem, katere podatke vrne vaše skladišče.

Super power-up: generiki

To bi lahko sprejeli še dlje, z uporabo generičnih izdelkov. Če razmislite, ima večina repozitorij vedno iste operacije

  1. dobil vse stvari
  2. dobil nekaj stvari
  3. vstavite nekaj stvari
  4. izbrisati stvar
  5. posodobiti stvar

No, edino, kar je drugače, je beseda "stvar", tako da je to morda odličen kandidat za uporabo protokola z generičnimi podatki. Morda se sliši zapleteno, a v resnici je to zelo enostavno storiti.

Najprej bomo protokol preimenovali v Repository, da bo bolj… generičen .
Potem bomo odstranili vse vrste člankov in jih nadomestili s čarovniškim T. Toda črka T je le nadomestilo za ... vse, kar želimo, da je. Moramo samo označiti T kot povezano vrsto protokola.

Zdaj lahko ta protokol uporabimo za kateri koli modelni objekt, ki ga imamo.

1. Repozitorij člankov

Prevajalnik bo sklepal na tip T v Article, saj smo z izvajanjem metod določili, kaj je T. V tem primeru predmet članka.

2. Uporabniško skladišče

To je to.

Upam, da vam je bil članek všeč in če imate kakršna koli vprašanja ali pripombe, jih postavite spodaj ali se dotaknite mene na Twitterju in naj se pogovorimo.