Как да изберем подходящата iOS архитектура (част 2)

MVC, MVP, MVVM, VIPER или VIP

Можете да се консултирате с част първа тук.

Основните iOS архитектури

Кратък преглед.

MVC

MVC слоевете са както следва:

М: Бизнес логика, мрежов слой и слой за достъп до данни

V: Слой на потребителския интерфейс (неща от UIKit, дъски за разкази, Xibs)

В: Координира посредничеството между Модел и Изглед.

За да разберем MVC, трябва да разберем контекста, в който е измислен. MVC е изобретен в старите дни на уеб разработката, където Views няма състояние. В старите времена всеки път, когато имаме нужда от визуална промяна в уебсайта, браузърът презарежда целия HTML отново. По онова време нямаше концепция за състоянието на изгледа да се поддържа и запазва.

Имаше например някои разработчици, които се смесват в един и същ HTML файл, PHP и достъп до база данни. Така че основната мотивация на MVC беше да отдели View View от моделния слой. Това увеличи проницаемостта на моделния слой. Предполага се, че в MVC слоят View и Model не трябва да знаят нищо един за друг. За да стане това възможно, е създаден посреднически слой, наречен Controller. Това беше SRP, което беше приложено.

Пример за MVC цикъла:

  1. Потребителско действие / събитие в View Layer (например: Refresh Action) се задейства и това действие се съобщава на Controller
  2. Контролерът, който задава данни на моделния слой
  3. Моделирайте данните за връщане към Controller
  4. Контролерът казва, че за актуализацията на изгледа се показва състоянието му с новите данни
  5. Преглед на актуализацията на неговото състояние

Apple MVC

В iOS View Controller е свързан с UIKit и изглед на жизнения цикъл, така че не е чист MVC. В дефиницията на MVC обаче нищо не се казва, че контролерът не може да знае специфичната реализация на View или Model. Основната му цел е да отдели отговорностите на моделния слой от слоя View, за да можем да го използваме повторно и да тестваме слоя Model изолирано.

ViewController съдържа изгледа и притежава модела. Проблемът е, че използвахме да пишем кода на контролера, както и кода на изгледа в ViewController.

MVC често създава наречения Massive View Controller проблем, но това се случва само и се превръща в сериозно нещо в приложенията с достатъчно сложност.

Има някои методи, които разработчикът може да използва, за да направи контролера на View по-управляем. Няколко примера:

  • Извличане на логиката VC за други класове като изглед на таблица методи източник на данни и делегат за други файлове с помощта на модела на делегат на дизайн.
  • Създайте по-ясно разделение на отговорностите със състав (напр. Разделете VC на контролери за изглед на деца).
  • Използвайте модела на дизайна на координатора, за да премахнете отговорността за прилагане на навигационната логика във ВК
  • Използвайте клас обвивка на DataPresenter, който капсулира логиката и трансформира модела на данни в изход от данни, представящ данните, представени на крайния потребител.

MVC срещу MVP

Как можете да видите диаграмата на MVP е много подобна на MVC

MVC беше крачка напред, но все още бе белязан от отсъствие или мълчание за някои неща.

Междувременно световната мрежа се разраства и много неща в общността на разработчиците се развиват. Например, програмистите започнаха да използват Ajax и зареждат само части от страниците, вместо цялата HTML страница.

В MVC мисля, че няма нищо, което да показва, че контролерът не трябва да знае конкретната реализация на View (отсъствие).

HTML беше част от слоя View и много случаи бяха тъпи като дяволи. В някои случаи той получава събития само от потребителя и показва визуалното съдържание на GUI.

Тъй като части от уеб страниците започнаха да се зареждат на части, тази сегментация доведе в посока поддържане на състояние View и по-голяма нужда от разделяне на логическата отговорност за презентация.

Логиката на презентацията е логиката, която контролира как трябва да се показва потребителският интерфейс и как елементите на потребителския интерфейс взаимодействат заедно. Пример е контролната логика за това кога даден индикатор за зареждане трябва да започне да се показва / анимира и кога трябва да спре да показва / анимира.

В MVP и MVVM View Layer трябва да е тъп като fuck, без никаква логика или интелигентност в него, а в iOS, View Controller трябва да е част от View Layer. Фактът, че View е тъп, означава, че дори логиката на представяне остава извън слоя View.

Един от проблемите на MVC е, че не е ясно къде трябва да остане логиката на представяне. Той просто мълчи за това. Трябва ли логиката на представяне да бъде в слоя View или в моделния слой?

Ако ролята на Модела е просто да предостави „сурови“ данни, това означава, че кодът в изгледа ще бъде:

Помислете следния пример: имаме потребител, с име и фамилия. В изгледа трябва да покажем потребителското име като „Фамилно име, име“ (напр. „Flores, Tiago“).

Ако ролята на Модела е да предоставя „сурови“ данни, това означава, че кодът в изгледа ще бъде:

нека firstName = userModel.getFirstName ()
нека lastName = userModel.getLastName ()
nameLabel.text = lastName + “,“ + firstName

Така че това означава, че отговорността за работа с логиката на потребителския интерфейс е отговорност на View. Но това прави логиката на потребителския интерфейс невъзможна за единичен тест.

Другият подход е моделът да изложи само данните, които трябва да бъдат показани, криейки всякаква бизнес логика от изгледа. Но след това приключваме с Модели, които се справят както с бизнес, така и с логиката на потребителския интерфейс. Това би било тестирано за единица, но след това Моделът приключва, като имплицитно зависи от изгледа.

нека име = userModel.getDisplayName ()
nameLabel.text = име

MVP е ясно за това и логиката на презентация остава в слоя Presenter. Това увеличава проницаемостта на слоя Presenter. Сега слоят модел и презентация са лесно тестваеми.

Обикновено в MVP реализациите, View е скрит зад интерфейс / протокол и не трябва да има препратки към UIKit в Presenter.

Друго нещо, което трябва да имате предвид, са преходните зависимости.

Ако контролерът има бизнес слой като зависимост, а бизнес слой има слой за достъп до данни като зависимост, тогава контролерът има преходна зависимост за слоя за достъп до данни. Тъй като реализациите на MVP обикновено използват договор (протокол) между всички слоеве, той няма преходни зависимости.

Различните слоеве също се променят по различни причини и с различна скорост. Така че, когато промените слой, не искате това да доведе до вторични ефекти / проблеми в другите слоеве.

Протоколите са по-стабилни от класовете. Протоколите нямат подробности за изпълнението и с договорите, така че е възможно да промените детайлите за изпълнение на слой, без това да засяга останалите слоеве.

Така договорите (протоколите) създават разединяване между слоевете.

MVP срещу MVVM

MVVM диаграма

Една от основните разлики между MVP и MVVM е, че в MVP презентаторът комуникира с изгледа чрез интерфейси, а в MVVM изгледът е ориентиран към промени в данни и събития.

В MVP правим ръчно обвързване между Presenter и View с помощта на интерфейси / протоколи.
В MVVM ние правим автоматично свързване на данни, използвайки нещо като RxSwift, KVO или използваме механизъм с генерични данни и затваряния.

В MVVM дори не се нуждаем от договор (напр .: java интерфейс / iOS протокол) между ViewModel и View, защото обикновено комуникираме през Observer Design Pattern.

MVP използва шаблона за делегиране, тъй като представителят на слоевете за презентации поръчва на View Layer, така че трябва да знае нещо за изгледа, дори ако е само подписът на интерфейса / протокола. Помислете за разликата между Центъра за известия и TableView Делегатите. Центърът за известяване не се нуждае от интерфейси, за да създаде комуникационен канал, но TableView Delegates използва протокол, който класовете трябва да внедрят.

Помислете за логиката на представяне на индикатор за зареждане. В MVP презентаторът прави ViewProtocol.showLoadingIndicator. В MVVM може да има свойство isLoading в ViewModel. Слоят View чрез автоматично обвързване на данни открива кога това свойство се променя и освежава. MVP е по-наложително от MVVM, защото Presenter дава заповеди.

MVVM е по-скоро за промените на данните, отколкото за директните поръчки и ние правим връзки между промените на данните и преглеждаме актуализации. Ако използвате парадигмата на RxSwift и функционално реактивно програмиране заедно с MVVM, ние направихме кода още по-малко наложителен и по-декларативен.

MVVM е по-лесен за тестване от MVP, тъй като MVVM използва модела за дизайн на наблюдателя, който прехвърля данни между компоненти по отделен начин.
Така че можем да тестваме само като разгледаме промените в данните, само като сравним двата обекта, а не да създаваме подигравки с методите за повикване на комуникацията между View и Presenter.

PS: Направих някои актуализации на статията, които я накараха да расте много, така че беше необходимо да я разделя на три части. Можете да прочетете част трета тук.

Част втора завършва тук. Всички отзиви са добре дошли. В трета част ще се говори за VIPER, VIP, реактивно програмиране, компромиси, ограничения и контекстуално чувство.

Благодаря ви за четенето! Ако тази статия ви е харесала, моля плеснете
така че и други хора могат да го прочетат :)