Si të zgjidhni arkitekturën e përshtatshme iOS (Pjesa 2)

MVC, MVP, MVVM, VIPER ose VIP

Ju mund të konsultoheni me pjesën e parë këtu.

Arkitekturat më të rëndësishme të iOS

Një përmbledhje e shkurtër.

MVC

Shtresat MVC janë si më poshtë:

M: logjika e biznesit, shtresa e rrjetit dhe shtresa e aksesit të të dhënave

V: Niveli i ndërfaqes së përdoruesit (objektet UIKit, tabela me tregime, Xibs)

C: Koordinon ndërmjetësimin midis modelit dhe pikëpamjes.

Për të kuptuar MVC duhet të kuptojmë kontekstin në të cilin është shpikur. MVC është shpikur në ditët e vjetra të zhvillimit të uebit kur Pamjet nuk kishin status. Në ditët e lashta, shfletuesi rimbush të gjithë HTML sa herë që kemi nevojë për një ndryshim vizual në faqen e internetit. Në atë kohë, nuk kishte ide se gjendja e pamjes po vazhdonte dhe ruhej.

Për shembull, ka pasur disa zhvillues që kanë përdorur të njëjtat skedarë HTML, PHP dhe aksesin e bazës së të dhënave. Pra, motivimi kryesor i MVC ishte të ndante nivelin e shikimit nga niveli i modelit. Kjo rrit testueshmërinë e nivelit të modelit. Gjoja në MVC pamja dhe shtresat e modelit nuk duhet të dinë për njëra-tjetrën. Për ta bërë të mundur këtë, u shpik një shtresë e ndërmjetme e quajtur kontrollues. Ky ishte PSR që u aplikua.

Një shembull i ciklit MVC:

  1. Shkaktohet një veprim i përdoruesit / një ngjarje përdoruesi në nivelin e shikimit (p.sh. "veprim i azhurnuar") dhe ky veprim i komunikohet kontrolluesit
  2. Kontrolluesi që dërgon të dhëna në nivelin e modelit
  3. Modeloni të dhënat e kthyera në kontrollues
  4. Kontrolluesi thotë se pamja do të azhurnojë statusin e saj me të dhënat e reja
  5. Shikoni azhurnoni gjendjen e tij

Apple MVC

Në iOS, Kontrolluesi i Pamjes shoqërohet me UIKit dhe pamjen e ciklit të jetës, kështu që nuk është një MVC i pastër. Sidoqoftë, në përkufizimin MVC nuk ka asgjë për të thënë që kontrolluesi nuk mund të di pamjen ose modelin e zbatimit specifik. Qëllimi i tij kryesor është të ndajë përgjegjësitë e nivelit të modelit nga niveli i pamjes në mënyrë që të mund t'i ripërdorim ato dhe të testojmë nivelin e modelit në mënyrë të izoluar.

ViewController përmban pamjen dhe zotëron modelin. Problemi është se ne po shkruajmë kodin e kontrolluesit dhe kodin e pamjes tek ViewController.

MVC shpesh shkakton atë që quhet problemi Massive View Controller, por kjo ndodh vetëm në aplikacione me mjaft kompleksitet dhe bëhet biznes serioz.

Ekzistojnë disa metoda që zhvilluesi mund të përdorë për ta bërë më të qartë kontrolluesin e pamjes. Disa shembuj:

  • Nxjerrni logjikën e QV-së për klasat e tjera siç është burimi i të dhënave të metodave të pamjes së tryezës dhe delegoni për skedarët e tjerë duke përdorur modelin e dizajnit të delegatëve.
  • Krijoni një ndarje më të qartë të përgjegjësive të përbërjes (p.sh., ndarja e QV-së në kontrollet e shikimit të fëmijëve).
  • Përdorni modelin e dizajnit të koordinatorit për të hequr përgjegjësinë për zbatimin e logjikës së navigimit në kontrolluesin virtual
  • Përdorni një klasë mbështjellëse DataPresenter që përmbledh logjikën dhe konverton modelin e të dhënave në dalje të të dhënave që përfaqësojnë të dhënat e paraqitura te përdoruesi përfundimtar.

MVC kundrejt MVP

Siç mund ta shihni diagramin nga MVP, MVC është shumë e ngjashme

MVC ishte një hap përpara, por ende shënohej nga një mungesë ose heshtje për disa gjëra.

Në ndërkohë, Rrjeti World Wide u rrit dhe shumë gjëra po zhvilloheshin në komunitetin e zhvilluesve. Për shembull, programuesit filluan të përdorin Ajax dhe ngarkojnë vetëm pjesë të faqeve në vend të të gjithë faqes HTML menjëherë.

Sipas MVC, për mendimin tim, nuk ka asnjë tregues që kontrolluesi nuk duhet të dijë zbatimin specifik të View (mungesës).

HTML ishte pjesë e shtresës së pamjes dhe shumë raste ishin kaq budallaqe. Në disa raste, ai thjesht merr ngjarje nga përdoruesi dhe shfaq përmbajtjen vizuale të GUI.

Ndërsa pjesë të faqeve të internetit u ngarkuan në pjesë, ky segmentim çoi në ruajtjen e gjendjes së shikimit dhe një nevojë më të madhe për ndarjen e përgjegjësive për logjikën e prezantimit.

Logjika e prezantimit është logjika që kontrollon se si duhet të shfaqet ndërfaqja e përdoruesit dhe si bashkëveprojnë elementet e ndërfaqes së përdoruesit me njëri-tjetrin. Një shembull është logjika e kontrollit se kur një tregues i ngarkimit duhet të fillojë të tregojë / animojë dhe kur duhet të ndalojë shfaqjen / gjallërimin.

Në MVP dhe MVVM, shtresa e pamjes duhet të jetë aq budalla sa nuk përmban asnjë logjikë ose inteligjencë, dhe në iOS kontrolluesi i pamjes duhet të jetë pjesë e shtresës së pamjes. Fakti që View është memec do të thotë që edhe logjika e prezantimit mbetet jashtë planit View.

Një nga problemet me MVC është se nuk është e qartë se ku duhet të shkojë logjika e prezantimit. Ai thjesht hesht për këtë. Logjika e prezantimit duhet të jetë në nivelin e shikimit apo në nivelin e modelit?

Nëse roli i modelit është të sigurojë vetëm "të dhënat e papërpunuara", kjo do të thotë që kodi në pamje është si më poshtë:

Merrni parasysh shembullin vijues: Ne kemi një përdorues me emër dhe mbiemër. Në pamje duhet të tregojmë emrin e përdoruesit si "Mbiemër, Emër" (p.sh. "Flores, Tiago").

Nëse roli i modelit është të sigurojë të dhëna "të papërpunuara", kjo do të thotë që kodi në pamje është si më poshtë:

le firstName = userModel.getFirstName () le lastName = userModel.getLastName () nameLabel.text = Mbiemri + “,“ + Emri

Kjo do të thotë që është përgjegjësia e View-ut të trajtojë logjikën e ndërfaqes së përdoruesit. Sidoqoftë, kjo e bën të pamundur testimin njësor të logjikës së ndërfaqes së përdoruesit.

Qasja tjetër është që modeli të tregojë vetëm të dhënat që duhen treguar dhe të fshehë logjikën e biznesit nga shikimi. Por pastaj kemi modele që trajtojnë si logjikën e biznesit ashtu edhe logjikën e ndërfaqes së përdoruesit. Do të ishte një entitet i testueshëm, por atëherë modeli në mënyrë implicite varet nga pamja.

le emrin = userModel.getDisplayName () nameLabel.text = emër

Kjo është e qartë për MVP dhe logjika e prezantimit mbetet në nivelin prezantues. Kjo rrit testueshmërinë e nivelit prezantues. Tani modeli dhe shtresa prezantuese mund të testohen pa ndonjë problem.

Zakonisht në implementimet e MVP pamja fshihet pas një ndërfaqe / protokolli dhe nuk duhet të ketë referenca për UIKit në prezantues.

Një tjetër gjë për t'u theksuar është varësia kalimtare.

Nëse kontrolluesi ka një shtresë biznesi si varësi dhe shtresa e biznesit ka një shtresë të hyrjes në të dhëna si varësi, kontrollori ka një varësi kalimtare për shtresën e hyrjes së të dhënave. Meqenëse implementimet e MVP zakonisht përdorin një kontratë (protokoll) midis të gjitha niveleve, nuk ka varësi kalimtare.

Shtresat e ndryshme ndryshojnë gjithashtu për arsye të ndryshme dhe me ritme të ndryshme. Pra, nëse ndërroni një nivel, kjo nuk supozohet se shkakton efekte / probleme dytësore në nivelet e tjera.

Protokollet janë më të qëndrueshëm se klasat. Regjistrat nuk përmbajnë ndonjë detaj të zbatimit dhe nuk janë të lidhur me kontratat. Prandaj, është e mundur të ndryshohen detajet e zbatimit të një niveli pa ndikuar në nivelet e tjera.

Kontratat (protokollet) krijojnë një shkëputje midis shtresave.

MVP vs MVVM

Diagrami MVVM

Një nga ndryshimet kryesore midis MVP dhe MVVM është se në MVP prezantuesi ndërfaqet me pamjen dhe në MVVM pamja përqendrohet në të dhënat dhe ndryshimet e ngjarjeve.

Në MVP ne krijojmë një lidhje manuale midis prezantuesit dhe pamjes duke përdorur ndërfaqet / protokollet. Në MVVM ne kryejmë një lidhje automatike të të dhënave me RxSwift, KVO ose një mekanizëm me gjenerikë dhe mbyllje.

Në MVVM nuk na duhet as një kontratë (p.sh. ndërfaqja Java / protokolli iOS) midis ViewModel dhe View, pasi normalisht komunikojmë përmes Modelit të Dizajnit të Vëzhguesit.

MVP përdor modelin e delegatit sepse shtresa prezantuese delegon komandat në shtresën e pamjes. Prandaj, ai duhet të dijë diçka për pamjen, edhe nëse është vetëm nënshkrimi i ndërfaqes / protokollit. Mendoni për ndryshimin midis Qendrës së Njoftimit dhe delegatëve të TableView. Qendra e Njoftimeve nuk ka nevojë për ndërfaqe për të krijuar një kanal komunikimi. Sidoqoftë, TableView Delegates përdor një protokoll që klasat duhet të zbatojnë.

Mendoni për logjikën e prezantimit të një treguesi të ngarkesës. Në MVP, prezantuesi ekzekuton ViewProtocol.showLoadingIndicator. Në MVVM, mund të ketë një pronë isLoading në ViewModel. Shtresa e shikimit përdor lidhjen automatike të të dhënave për të njohur kur kjo pronë ndryshon dhe azhurnohet vetë. MVP është më tërheqës sesa MVVM sepse prezantuesi lëshon komanda.

MVVM ka të bëjë më shumë me ndryshimet e të dhënave sesa me porositë e drejtpërdrejta dhe ne i lidhim ndryshimet e të dhënave për të parë azhurnimet. Kur përdorim RxSwift dhe një paradigmë funksionale funksionuese të programimit së bashku me MVVM, ne e kemi bërë kodin edhe më pak tërheqës dhe më deklarativ.

MVVM është më e lehtë për tu provuar sesa MVP, pasi MVVM përdor Modelin e Projektimit të Vëzhguesit, i cili transferon të dhëna ndërmjet përbërësve në një mënyrë të shkëputur. Kështu që ne mund të testojmë duke parë vetëm ndryshimet në të dhëna duke krahasuar dy objektet, në vend që të tallemi me thirrjet e metodës për të provuar komunikimin midis pamjes dhe prezantuesit.

PS: Kam bërë disa azhurnime të artikullit që e bëri atë të rritet shumë. Prandaj ishte e nevojshme të ndahej në tre pjesë. Pjesën e tretë mund ta lexoni këtu.

Pjesa e dytë përfundon këtu. Të gjitha reagimet janë të mirëseardhura. Pjesa e tretë ka të bëjë me VIPER, VIP, Programim Reaktiv, Shkëmbime, Kufizime dhe Ndjenjë Konteksuale.

Faleminderit per leximin! Nëse ju ka pëlqyer ky artikull, ju lutem duartrokisni që të tjerët ta lexojnë gjithashtu :)