A megfelelő iOS architektúra kiválasztása (2. rész)

MVC, MVP, MVVM, VIPER vagy VIP

Itt megtekintheti az első részt.

A fő iOS-architektúrák

Rövid áttekintés.

MVC

Az MVC rétegek a következők:

M: Üzleti logika, hálózati réteg és adathozzáférési réteg

V: UI réteg (UIKit dolgok, Storyboards, Xibs)

C: Koordinálja a modell és a nézet közötti közvetítést.

Az MVC megértése érdekében meg kell értenünk azt a környezetet, amelyben kitalálták. Az MVC-t a régi webfejlesztési napokban találták ki, ahol a Views nem rendelkezik állammal. A régi időkben minden alkalommal, amikor vizuális változtatásra van szükségünk a webhelyen, a böngésző újból tölti be a teljes HTML-t. Abban az időben nem volt fogalom a nézet állapotának fenntartásáról és mentéséről.

Volt néhány fejlesztő, akik keveredtek ugyanabban a HTML fájlban, a PHP-ben és az adatbázis-hozzáférésben. Tehát az MVC fő motivációja a View réteg és a Model réteg elválasztása volt. Ez növelte a modellréteg tesztelhetőségét. Állítólag az MVC-ben a Nézet és a Modell rétegnek semmit sem kell tudnia egymásról. Ennek megvalósításához egy Controller nevû köztes réteget találtak ki. Ez volt az SRP, amelyet alkalmaztak.

Példa az MVC ciklusra:

  1. A felhasználói művelet / esemény a nézetrétegben (például: Frissítési művelet) elindul, és erről a műveletről értesítik a Vezérlőt
  2. Az a vezérlő, amely adatokat kér a modellrétegtől
  3. Modellezze az adatokat a Vezérlőhöz
  4. A vezérlő azt mondja, hogy a Nézet frissítse állapotát az új adatokkal
  5. Nézet frissítse az államát

Apple MVC

Az iOS rendszerben a View Controller csatolva van az UIKit és az életciklus nézethez, tehát nem pusztán MVC. Az MVC meghatározásában azonban semmi nem azt jelenti, hogy a Vezérlő nem ismeri a Nézet vagy a Modell specifikus megvalósítását. Fő célja a modellréteg és a nézetréteg felelősségének elkülönítése, hogy újra felhasználhassuk és a modellréteget elvégezzük elszigetelten.

A ViewController tartalmazza a View nézetet és a modell tulajdonosa. A probléma az, hogy a vezérlőkódot, valamint a nézetkódot a ViewControllerbe írjuk.

Az MVC gyakran létrehozza az úgynevezett Massive View Controller problémát, de ez csak akkor fordul elő, és komoly dologgá válik az elég bonyolult alkalmazásokban.

Van néhány módszer, amelyet a fejlesztő használhat a View Controller kezelhetőbbé tételéhez. Néhány példa:

  • Kicsomagoljuk a VC logikát más osztályokhoz, például a táblázatnézet módszert az adatforráshoz, és más fájlokhoz delegáljuk a delegált tervezési mintával.
  • Hozzon létre egyértelműbben a felelősségi körök összetételét (például ossza fel a VC-t a gyermeknéző vezérlőkre).
  • A koordinátor tervezési mintájának alkalmazásával távolítsa el a navigációs logika virtuális vezérlőben történő végrehajtásának felelősségét
  • Használjon egy DataPresenter burkolóosztályt, amely magába foglalja a logikát, és az adatmodellt a végfelhasználónak bemutatott adatokat képviselő adatkimenetté alakítja.

MVC vs MVP

Az MVP diagramjának látása nagyon hasonló az MVC-hez

Az MVC előrelépés volt, ám néhány dolgot mégis hiány vagy csend jellemezte.

Időközben nőtt a világháló, és a fejlesztők közösségében sok minden fejlődött. Például a programozók elkezdték az Ajax használatát, és csak az oldalak egy részét töltik be a teljes HTML oldal helyett.

Az MVC-ben úgy gondolom, hogy semmi nem utal arra, hogy a vezérlőnek nem kellene tudnia a View (távollét) konkrét megvalósítását.

A HTML a Nézet réteg része volt, és sok eset hülye, mint szar. Egyes esetekben csak a felhasználóktól kap eseményeket, és megjeleníti a grafikus felhasználói felület vizuális tartalmát.

Mivel a weblapok egyes részeit részletekbe töltötték, ez a szegmentálás a View állapot fenntartásának irányába vezetett, és egyre nagyobb szükség volt a bemutató logikai felelősség elkülönítésére.

A prezentációs logika az a logika, amely szabályozza, hogy a felhasználói felület hogyan jelenjen meg, és hogy a felhasználói felület elemei miként működnek együtt. Példa erre a vezérlő logika, amikor a terhelésjelző indulni kell / animálni, és mikor kell abbahagyni a megjelenítés / animálást.

Az MVP és az MVVM esetében a nézetrétegnek tompa, mint szar, logika vagy intelligencia nélkül, és az iOS rendszerben a nézetvezérlőnek a nézetréteg részét kell képeznie. Az a tény, hogy a nézet néma, azt jelenti, hogy még a prezentációs logika is kimarad a Nézet rétegből.

Az MVC egyik problémája az, hogy nem egyértelmű, hogy a prezentációs logika hol tartson. Erről egyszerűen csak hallgat. A prezentációs logikának a Nézet rétegben vagy a Modellrétegben kell lennie?

Ha a modell szerepe csupán a „nyers” adatok megadása, akkor ez azt jelenti, hogy a nézetben a következő kód lenne:

Vegyük figyelembe a következő példát: Van egy felhasználó, akinek utóneve és vezetékneve van. A Nézetben a felhasználónevet „Vezetéknév, keresztnév” -ként kell megjeleníteni (pl. „Flores, Tiago”).

Ha a modell szerepe a „nyers” adatok megadása, ez azt jelenti, hogy a nézetben a következő kód lenne:

let firstName = userModel.getFirstName ()
let lastName = userModel.getLastName ()
nameLabel.text = lastName + “,“ + firstName

Tehát ez azt jelenti, hogy a felhasználói felület logikájának kezelése a nézet felelőssége. Ez azonban az UI logikáját lehetetlenné teszi az egységteszt elvégzéséhez.

A másik megközelítés az, hogy a modell csak azokat az adatokat tegye ki, amelyeket megjeleníteni kell, és elrejti az üzleti logikát a nézetből. De aztán olyan modellekkel járunk, amelyek üzleti és felhasználói felület logikát is kezelnek. Egység tesztelhető lenne, de akkor a modell végül véletlenül függ a nézettől.

let name = userModel.getDisplayName ()
nameLabel.text = név

Az MVP tisztában van ezzel, és a bemutató logika a Presenter rétegben marad. Ez növeli a Presenter réteg tesztelhetőségét. Most a Model és az Presenter Layer könnyen tesztelhető.

Általában az MVP megvalósításokban a nézet egy interfész / protokoll mögött van elrejtve, és az Presenterben nem szabad hivatkozni az UIKit-re.

Egy másik dolog, amelyet szem előtt kell tartani, a tranzitív függőségek.

Ha a vezérlőnek üzleti rétege van függőségként, és az üzleti rétegnek adathozzáférési rétege van, akkor a vezérlőnek átmeneti függősége van az adathozzáférési rétegre. Mivel az MVP megvalósítások rendszerint egy szerződést (protokollt) használnak az összes réteg között, ennek nincs tranzitív függősége.

A különböző rétegek különböző okokból és eltérő ütemben változnak. Tehát, amikor megváltoztat egy réteget, nem akarja, hogy ez másodlagos hatásokat / problémákat okozzon a többi rétegben.

A protokollok stabilabbak, mint az osztályok. A protokollok nem tartalmaznak részleteket és a szerződéseket, tehát meg lehet változtatni egy réteg végrehajtási részleteit anélkül, hogy a többi réteget befolyásolná.

Tehát a szerződések (protokollok) elválasztják a rétegeket.

MVP vs MVVM

MVVM diagram

Az MVP és az MVVM közötti fő különbség az, hogy az MVP-ben az Presenter interfészek útján kommunikál a View-kel, az MVVM-ben a View az adatokra és az események változására irányul.

Az MVP-ben kézi kötést készítünk a Presenter és a View között Interfészek / Protokollok segítségével.
Az MVVM-ben automatikus adatkötést készítünk, például RxSwift, KVO, vagy generikus és záró mechanizmussal.

Az MVVM-ben még nincs szükségünk szerződésre (pl .: java interfész / iOS protokoll) a ViewModel és a View között, mert általában a Observer Design mintán keresztül kommunikálunk.

Az MVP a Delegált mintát használja, mert a Presenter Layer delegálja a View Layer-t, így tudnia kell valamit a View-ról, még akkor is, ha csak a felület / protokoll aláírása van. Gondoljon a különbségre az értesítési központ és a TableView küldöttek között. A Notification Center-nek nincs szüksége interfészekre a kommunikációs csatorna létrehozásához, de a TableView Delegates olyan protokollt használ, amelyet az osztályoknak végre kell hajtaniuk.

Gondolj a betöltési mutató bemutatási logikájára. Az MVP-ben az előadó végrehajtja a ViewProtocol.showLoadingIndicator programot. Az MVVM-ben lehet egy isLoading tulajdonság a ViewModel-ben. A Nézet réteg automatikus adatkötés révén észleli, mikor változik ez a tulajdonság, és frissíti magát. Az MVP kényszerítőbb, mint az MVVM, mert az Presenter parancsokat ad.

Az MVVM inkább az adatváltozásokról szól, mint a közvetlen megrendelésekről, és asszociálunk az adatváltozások és a nézetfrissítések között. Ha az RxSwift és a funkcionális reaktív programozási paradigmát használja az MVVM-mel együtt, akkor a kódot még kevésbé kötelezővé és deklaratívabbá tettük.

Az MVVM-et könnyebben tesztelni lehet, mint az MVP-t, mert az MVVM a Observer Design mintát használja, amely elválasztja az adatokat az összetevők között.
Tehát csak akkor tesztelhetjük, ha az adatok változására figyelünk, csupán a két objektum összehasonlításával, ahelyett, hogy gúnyolódást hoznánk a metódushívásokkal, hogy teszteljük a View és az Presenter közötti kommunikációt.

PS: Megújítottam a cikket, amelyek miatt a cikk sokat nőtt, ezért három részre kellett felosztani. A harmadik rész itt olvasható.

A második rész itt ér véget. Minden visszajelzés örvendetes. A harmadik rész a VIPER-ről, a VIP-ről, a reaktív programozásról, a kompromisszumokról, a korlátozásokról és a kontextuális értelemről szól.

Köszönöm hogy elolvastad! Ha tetszett ez a cikk, kérlek tapsolj!
így mások is elolvashatják :)