Model de proiectare a depozitului în Swift

Un mod curat de a vă întreba modelele

Ce problemă rezolvă?

Dacă trebuie să vă interogați obiectele model din diferite locații ale codului dvs., o dată și deodată, un depozit poate fi cu adevărat util pentru a oferi un punct de intrare unică pentru a lucra cu modelele dvs. și pentru a elimina codul de interogare duplicat. Puteți să o luați și mai departe și să o utilizați cu protocoale, în acest mod puteți să eliminați cu ușurință implementările (de exemplu pentru testele unitare) sau îl puteți utiliza cu generice pentru a face o mai mare * tambur * abstracție generică. În acest articol voi acoperi toate aceste cazuri.

Schițând scena.

Să presupunem că aveți un cod care preia date dintr-o API și mapează acest lucru pentru a modela obiecte. În acest exemplu, voi prelua o listă de articole de pe un server.

Acest lucru poate părea un pic funky, dar este doar RxSwift, folosind Moya ca strat de abstractizare a rețelei, dar asta nu contează cu adevărat să înțelegem ce se întâmplă. Modul în care vă regăsiți datele depinde în totalitate de dvs.

Această bucată de cod face

  1. O solicitare GET către server
  2. Mapează JSON-ul returnat într-o serie de obiecte articol
  3. Închiderea este apelată la finalizarea tuturor lucrărilor.

De ce avem nevoie de un depozit?

Ei bine, în momentul de față, nu. Dacă apelați API-ul doar o singură dată în întreaga bază de cod, adăugarea unui depozit ar putea fi excesiv (sau cum ar putea spune unii peste inginerie).

Ok ... dar când este ușor de folosit un obiect de depozitare?
Să presupunem că baza dvs. de cod începe să crească și că trebuie să scrieți codul pentru a obține articolele încă o dată. S-ar putea să spuneți „să copiem codul și să-l lipiți oriunde aveți nevoie pentru a obține toate articolele.”

Nu s-a făcut rău, nu a murit nimeni. Dreapta?

În acel moment, o alarmă roșie mare ar trebui să înceapă să lumineze în creierul tău.

Salut depozit

Un depozit este doar un obiect care încapsulează tot codul pentru a interoga modelele dvs. într-un singur loc, deci aveți un punct de intrare unic dacă doriți, de ex. obține toate articolele.

Să creăm un obiect de depozit care oferă o API publică pentru a obține articolele.

Acum putem apela această metodă și nu trebuie să ne facem griji cu privire la ce se întâmplă în culise pentru a obține articolele reale.
Numiți doar metoda și primiți articolele. Frumos, nu?
Dar stai, există mai mult!

Gestionează toate interacțiunile articolului

Putem folosi depozitul pentru a adăuga mai multe metode pentru a interacționa cu obiectul nostru de model. De cele mai multe ori doriți să efectuați operații CRUD (creați, citiți, actualizați, ștergeți) pe modelul dvs. Ei bine, trebuie doar să adăugați logica pentru aceste operațiuni în depozit.

Acest lucru face ca o API plăcută să fie utilizată pe tot codul dvs., fără a fi nevoie să repetați același cod încă o dată.

În practică, utilizarea unui depozit ar arăta astfel.

Destul de frumos și de citit, nu? Dar, așteaptă să devină și mai bine.

Power-up: protocoale

În codul anterior, am folosit întotdeauna exemplul „obținerea de date dintr-o API”. Dar dacă doriți să adăugați suport pentru a încărca date dintr-un fișier JSON local, în loc de o sursă online.

Ei bine, dacă creați un protocol care listează numele metodei, puteți crea o implementare pentru API-ul online și una pentru a obține datele offline.

Acest lucru ar putea arăta astfel.

Un protocol spune doar „dacă sunteți conform cu mine, trebuie să aveți aceste metode semnături, dar nu-mi pasă de implementarea reală!”

Deci, este excelent, puteți crea un WebArticleRepository și un LocalArticleRepository. Ambele au toate metodele care sunt enumerate în protocol, dar puteți scrie 2 implementări total diferite.

Power-up: Testarea unității

Utilizarea protocoalelor este, de asemenea, foarte convenabilă atunci când doriți să vă testați codul, deoarece puteți crea un alt obiect care implementează protocolul de depozitare, dar în schimb returnează date batjocoritoare.

Dacă utilizați acest lucru împreună cu injecția de dependență, face foarte ușor să testați un anumit obiect.

Un exemplu

Să presupunem că aveți un model de vizualizare, iar modelul de vizualizare își primește datele printr-un depozit.

Dacă doriți să testați modelul de vizualizare, sunteți blocați cu articolele care vor fi preluate de pe web.
Acest lucru nu este ceea ce ne dorim. Ne dorim ca testul nostru să fie cât mai determinist. În acest caz, articolele preluate de pe web s-ar putea schimba în timp, nu ar putea exista nicio conexiune la internet la momentul efectuării testelor, serverul ar putea fi jos, ... acestea sunt toate scenariile posibile în care testele noastre ar putea eșua, deoarece acestea sunt în afara controlului nostru. Iar când testăm, vrem / trebuie să fim sub control.

Din fericire, este într-adevăr simplu de rezolvat acest lucru.

Buna ziua, injectie de dependenta.

Trebuie doar să setați proprietatea articleRepo prin inițializator. Cazul implicit va fi cel pe care îl doriți pentru codul dvs. de producție și atunci când scrieți un test de unitate, puteți schimba depozitul cu versiunea dvs. de tipar.

Dar poate te gândești, dar ce zici de tipuri? Un WebArticleRepository nu este un MockArticleRepository, deci compilatorul nu se va plânge? Ei bine, nu dacă folosești protocolul ca tip. În acest fel, informăm compilatorul, permitem totul atât timp cât acesta se conformează protocolului ArticleRepository (pe care îl fac atât Webul cât și MockArticleRepository).

Codul final ar arăta astfel.

Și în testul unității tale îl poți schimba astfel.

Acum aveți control deplin asupra datelor ce returnează depozitul dvs.

Super putere: generice

Puteți duce acest lucru și mai departe, folosind generice. Dacă vă gândiți, majoritatea depozitelor au întotdeauna aceleași operațiuni

  1. ia toate lucrurile
  2. obțineți câteva lucruri
  3. inserați câteva lucruri
  4. șterge ceva
  5. actualizați un lucru

Ei bine, singurul lucru diferit este cuvântul „lucru”, deci ar putea fi un candidat excelent pentru a utiliza un protocol cu ​​generice. S-ar putea să pară complicat, dar de fapt este destul de simplu de făcut.

Mai întâi vom redenumi protocolul în Repository, pentru a-l face mai… generic .
Și atunci vom elimina toate tipurile de articole și le vom înlocui cu T. magice. Dar litera T este doar un înlocuitor pentru… orice am dori să fie. Trebuie doar să marcăm T ca tip asociat al protocolului.

Deci, acum putem folosi acest protocol pentru orice obiect de model pe care îl avem.

1. Depozitul articolului

Compilatorul va deduce tipul T la articol, deoarece implementând metodele, am specificat care este T. În acest caz, un obiect articol.

2. Depozitul utilizatorului

Asta e.

Sper că v-a plăcut articolul și dacă aveți întrebări sau observații, cereți-le mai jos sau accesați-mi pe Twitter și să avem un chat.